Springboot+JPA下實現簡易爬蟲--爬取豆瓣電視劇資料
Springboot+JPA下實現簡易爬蟲--爬取豆瓣電視劇資料
前言:今天聽到產品那邊討論一些需求,好像其中一點是使用者要求我們爬蟲,在網頁上抓取一些資料然後存到我們公司資料庫中,眾所周知,爬蟲的實現對於python語言可是專家,而對於我們使用的Java語言,我也不確定可不可以,趁著無事,上網參考了下資料,自己也寫了些demo,所幸爬取資料成功了,由於我使用的基礎demo專案是自己搭建的springboot+jpa的專案,因此也會在這個基礎上進行爬蟲的實現,文章會貼出具體的步驟以及重要的程式碼,至於專案的搭建就不介紹了,我的完整程式碼會同步至gitHub,大家可以參考使用,當然也可以使用自己的springboot專案。
gitHub地址:https://github.com/Slience-zae/mail-demo.git
1.材料準備
1.1首先開啟豆瓣的網頁,同時F12開啟控制檯
1.2 在控制檯中找到介面url,請求頭資訊,以及相應資料格式和欄位
在網頁上準備的材料這些就可以了,接下來,該動手撰寫程式碼了。
2.程式碼實現步驟
2.1 資料庫建立表格
CREATE TABLE `subjects` ( `id` varchar(255) NOT NULL COMMENT 'id', `title` varchar(255) DEFAULT NULL COMMENT '標題', `rate` decimal(10,2) DEFAULT NULL COMMENT '豆瓣評分', `url` varchar(255) DEFAULT NULL COMMENT '觀影地址', `playable` tinyint(4) DEFAULT NULL COMMENT '是否可以觀看:0是 1否', `cover` varchar(255) DEFAULT NULL COMMENT '封面圖片地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
通過相應資料可以得知共有九個欄位,但是我們主要儲存的是資料主要資訊,其中cover_x,cover_y,is_new對於我們來說沒有什麼意義,可以不儲存到資料庫,因此略過。
2.2 hibernate逆向生成實體
選中右鍵點選,選擇Generate persistence Mapping,再選擇By Database Schema,選中資料庫的表,再選擇生成實體的包位置,最後點選ok就能生成到指定位置了,生成後我們再加以修改一下實體,大體是這個樣子。
import lombok.Data; import javax.persistence.*; import java.math.BigDecimal; @Data @Entity @Table(name = "subjects") public class Subjects { @Id private String id;//id private String title;//標題 private BigDecimal rate;//豆瓣評分 private String url;//觀影地址 private Boolean playable;//是否能夠觀看 private String cover;//封面圖片URL @Transient private Integer cover_x; @Transient private Integer cover_y; @Transient private Boolean is_new; }
在此說明一下,之所以將cover_x,cover_y,is_new三個欄位也新增進實體了,是為了防止接下來json陣列轉化List<Subjects>時發生異常,我已經在這三個欄位上加了@Transient註解,因此三個欄位不會對映資料庫。
2.3 編寫向指定網址抓取json資料的工具類
import org.springframework.boot.configurationprocessor.json.JSONObject; import org.springframework.stereotype.Component; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; @Component public class GetJson { public JSONObject getHttpJson(String url){ try { URL realUrl = new URL(url); HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection(); //設定HTTP的請求頭(參考材料準備截圖的請求頭資訊) connection.setRequestProperty("Accept", "*/*");//設定瀏覽器可以接收的媒體型別 connection.setRequestProperty("Connection", "keep-alive");//網頁開啟,建立連線 connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3928.4 Safari/537.36");//客戶端使用的作業系統和瀏覽器的名稱和版本 // 建立實際的連線 connection.connect(); //請求成功 if (connection.getResponseCode() == 200) { InputStream is = connection.getInputStream(); //建立位元組陣列輸出流物件 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); //10MB的快取 byte[] buffer = new byte[10485760]; int len = 0; while ((len = is.read(buffer))!= -1) { byteArrayOutputStream.write(buffer, 0, len); } String jsonString = byteArrayOutputStream.toString(); byteArrayOutputStream.close(); is.close(); //轉換成json資料返回 return new JSONObject(jsonString); } } catch (Exception e) { e.printStackTrace(); } return null; } }
注意一點,設定連線物件的請求頭資訊的時候,要將我們在豆瓣上拿到的那幾個引數設定成一樣的,防止抓取資料失敗,具體那幾個引數是什麼,已經在程式碼註釋上加以說明了。
2.4 完整業務程式碼糅合實現
(1).在application.properties配置檔案中加入以下程式碼
#豆瓣網址 douban_url= https://movie.douban.com/j/search_subjects
(2) dao層加入類
import com.maven.maildemo.entity.Subjects; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; public interface SubjectsDao extends CrudRepository<Subjects, String>, JpaSpecificationExecutor<Subjects> { }
(3) service,serviceImpl,controller層程式碼
import com.maven.maildemo.entity.Subjects; import java.util.List; public interface SubjectsService { /** * 在豆瓣網頁上抓取電視劇資訊儲存並返回 * @author zae * @param pageNumber 頁碼 */ List<Subjects> getAndSaveSubjectsList(Integer pageNumber) throws Exception; }
import com.alibaba.fastjson.JSON; import com.maven.maildemo.dao.SubjectsDao; import com.maven.maildemo.entity.Subjects; import com.maven.maildemo.service.SubjectsService; import com.maven.maildemo.utils.GetJson; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.configurationprocessor.json.JSONArray; import org.springframework.boot.configurationprocessor.json.JSONObject; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; @Slf4j @Service @Transactional public class SubjectsServiceImpl implements SubjectsService { @Value("${douban_url}") private String doubanUrl; @Autowired private GetJson getJson; private final String DOUBAN_PARM = "?type=tv&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start="; @Autowired private SubjectsDao subjectsDao; @Override public List<Subjects> getAndSaveSubjectsList(Integer pageNumber) throws Exception { if(pageNumber>=0 && pageNumber <= 10000){ String address = doubanUrl+DOUBAN_PARM+pageNumber; //獲取json物件資料 JSONObject httpJson = getJson.getHttpJson(address); if(httpJson != null){ //取出json資料陣列 JSONArray subjectsArray = httpJson.getJSONArray("subjects"); if(subjectsArray!=null){ //將json陣列轉化為List List<Subjects> subjectsList = JSON.parseArray(subjectsArray.toString(),Subjects.class); for(Subjects subjects:subjectsList){ //爬出資料後,儲存在資料庫中 subjectsDao.save(subjects); } return subjectsList; }else{ return new ArrayList<>(); } }else{ return new ArrayList<>(); } } return new ArrayList<>(); } }
import com.alibaba.fastjson.JSON; import com.maven.maildemo.entity.Subjects; import com.maven.maildemo.service.SubjectsService; import io.swagger.annotations.Api; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("subjects") @Api(description = "豆瓣") public class SubjectsController { @Autowired private SubjectsService subjectsService; /** * 在豆瓣網頁上抓取電視劇資訊儲存並返回 * @param pageNumber 頁碼 * @author zae * @return */ @GetMapping(value = "/getAndSaveSubjectsList") String getAndSaveSubjectsList(@RequestParam Integer pageNumber){ try { List<Subjects> subjectsList = subjectsService.getAndSaveSubjectsList(pageNumber); return subjectsList==null?null: JSON.toJSONString(subjectsList); } catch (Exception e) { return "爬取資料資訊發生異常"+e.getMessage(); } } }
業務程式碼沒啥複雜的,基本上都加註釋了,看一下就好了。
3.測試
啟動專案,開啟swaager,找到剛剛寫的介面,輸入引數點選進行測試。
此時不出意外應該是執行成功了,開啟資料庫,看一下庫裡有沒有我們爬下來的資料。
發現庫裡有值,說明我們已經成功的將資料爬下來了。不僅僅豆瓣如此,其他網頁資料也是類似的實現。
本人java爬蟲學習借鑑部落格:https://blog.csdn.net/qwe86314/article/details/91450098 博主是使用的mybatis結合實現,而我的是結合springboot+jpa的專案使用的。
如有問題,多多評論指教,文章編寫不易,期待您的推薦和贊,
&n