VW-Crawler
背景
自己一直對爬蟲比較感興趣,大學的畢業論文也是一個爬蟲項目(爬教務處信息,然後做了個Android版教務管理系統,還獲得了優秀畢業設計的稱號),自那以後遇到自己感興趣的網站就會去抓一下。前段時間工作上需要一些JD信息,我就從網上找了個開源的爬蟲框架WebMagic,使用簡單,易配置,功能也很強大,當然了也有些網站的數據不適合使用。前前後後寫了不下十幾個,慢慢的就想是不是可以把這些爬蟲代碼再抽象出來,做出一個簡易的爬蟲框架呢?於是就嘗試去看WebMagic的源碼,後來又發現了一個源碼比較容易解讀的爬蟲框架XXL-CRAWLER,簡單的分析了源碼之後,開發自己一套爬蟲框架的慾望更加強烈,於是在2017年底的時候就開始了開發,中間斷斷續續得停了寫,寫了停。直到最近8月底的時候纔算出了一個版本,然後順勢把它放到了Maven公服倉庫上。一個人的力量很薄弱,要想完善這個爬蟲的健壯性、可用性和易擴展性還需要大家的力量!
特點
- 語言: Java開發,框架比較簡單,多處使用的是接口編程,是學習Java不錯的例子
- 難度: 及其簡單,配置一下,寫個解析邏輯,整理下保存方法,就OK了
- 輕量: 使用Jsoup做默認的下載器,依賴性較低
- 線程: 可自主設置線程數抓取,提高抓取效率
- 重試: 支持失敗重試,次數可以自定義
- 代理: 支持配置代理池,默認隨機使用代理IP,也可自定義算法獲取
- 去重: 雙重去重,默認對URL去重,也可以定義第二層去重邏輯
- 控制: 可自主控制是否需要解析頁面,減少資源的使用
- 精準: 通過設置URL的正則來精準的解析每一個URL
- 擴展: 幾乎每一個環節都可以自定義
使用
使用Maven
在http://search.maven.org上使用最新的版本
在pom中引入
<dependency>
<groupId>com.github.vector4wang</groupId>
<artifactId>vw-crawler</artifactId>
<version>${last.version}</version>
</dependency>
離線使用
可以在項目主頁的release下載最新版本jar,然後導入自己的項目中。
步驟
- 配置參數
- 抽象正則
- 解析頁面
- 保存數據
各環節均支持自定義
示例
抓取CSDN某用戶的博客內容
設置爬蟲的基本配置,如User-Agent、起始地址、目標頁面的url正則表達式、線程數和超時時間等
new VWCrawler.Builder()
// 配置參數
.setHeader("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36") // 設置請求頭
.setUrl("https://blog.csdn.net/qqhjqs") // 設置爬蟲起始地址
.setThreadCount(10) // 設置幾個線程抓取數據
.setTimeOut(5000) // 設置超時時間
// 抽象正則
.setTargetUrlRex("https://blog.csdn.net/qqhjqs/article/details/[0-9]+") // 設置目標頁面url的正則表達式
// 解析頁面
.setPageParser(new CrawlerService<Blog>() {
/**
* 有的url可能在某個場景下不需要可在此處理
* 默認返回false,可以不做處理
* @param url 即將要抓取的url
* @return
*/
@Override
public boolean isExist(String url) {
if ("https://blog.csdn.net/qqhjqs/article/details/79101846".equals(url)) {
return true;
}
return false;
}
/**
* 有的頁面有WAF,可以再真正解析前,做個判斷,遇到特殊標誌的直接可以跳過
* 默認返回true,可以不做處理
* @param document 即將要解析的document
* @return
*/
@Override
public boolean isContinue(Document document) {
if ("最近和未來要做的事 - CSDN博客".equals(document.title())) {
System.out.println("模擬遇到WAF此頁面不做解析");
return false;
}
return true;
}
/**
* 目標頁面的doc對象,還有通過註解處理後的對象
* @param doc 文檔內容
* @param pageObj 封裝的對象
*/
@Override
public void parsePage(Document doc, Blog pageObj) {
// 可進行二次處理
pageObj.setReadNum(pageObj.getReadNum().replace("閱讀數:", ""));
}
// 保存數據
/**
* 可以做保存對象的處理
* @param pageObj 頁面對象
*/
@Override
public void save(Blog pageObj) {
System.out.println("save blog summery: " + pageObj.toString());
}
}) // 自定義解析service
.build().start(); // 啓動
配置頁面數據對象的註解
@CssSelector(selector = "#mainBox > main > div.blog-content-box > div.article-title-box > h1", resultType = SelectType.TEXT)
private String title;
@CssSelector(selector = "#mainBox > main > div.blog-content-box > div.article-info-box > div > span.time", dateFormat = "yyyy年MM月dd日 HH:mm:ss")
private Date lastUpdateDate;
@CssSelector(selector = "#mainBox > main > div.blog-content-box > div.article-info-box > div > div > span", resultType = SelectType.TEXT)
private String readNum;
這裏使用比較流行的註解方式,通過cssselector來獲取節點數據可通過resultType來指定填充的是text還是html。
隨便配置一下,就能抓取一個頁面的數據
new VWCrawler.Builder().setUrl("https://www.qiushibaike.com/").setPageParser(new CrawlerService() {
@Override
public void parsePage(Document doc, Object pageObj) {
System.out.println(doc.toString());
}
@Override
public void save(Object pageObj) {
}
}).build().start();
更多
更多的示例可移步more
抓取了足夠多的數據,我們可以拿數據做很多事,比如統計各大人才網的職位分佈圖
有關ES的可移步這裏
最後
輪子造多了就想着造一個模具,代碼寫多了就想寫個框架,一樣的道理。幫助他人,順便提升自己。框架還有很多需要完善的地方,希望使用者多多提issue,也希望大家提PR~~~