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的專案使用的。
如有問題,多多評論指教,文章編寫不易,期待您的推薦和贊,