VW-Crawler
背景
自己一直對爬蟲比較感興趣胎源,大學的畢業(yè)論文也是一個爬蟲項目(爬教務處信息棉钧,然后做了個Android版教務管理系統(tǒng),還獲得了優(yōu)秀畢業(yè)設計的稱號)涕蚤,自那以后遇到自己感興趣的網站就會去抓一下宪卿。前段時間工作上需要一些JD信息,我就從網上找了個開源的爬蟲框架WebMagic万栅,使用簡單佑钾,易配置,功能也很強大烦粒,當然了也有些網站的數據不適合使用休溶。前前后后寫了不下十幾個,慢慢的就想是不是可以把這些爬蟲代碼再抽象出來扰她,做出一個簡易的爬蟲框架呢兽掰?于是就嘗試去看WebMagic的源碼,后來又發(fā)現了一個源碼比較容易解讀的爬蟲框架XXL-CRAWLER,簡單的分析了源碼之后徒役,開發(fā)自己一套爬蟲框架的欲望更加強烈,于是在2017年底的時候就開始了開發(fā)孽尽,中間斷斷續(xù)續(xù)得停了寫,寫了停忧勿。直到最近8月底的時候才算出了一個版本杉女,然后順勢把它放到了Maven公服倉庫上瞻讽。一個人的力量很薄弱,要想完善這個爬蟲的健壯性熏挎、可用性和易擴展性還需要大家的力量速勇!
特點
- 語言: Java開發(fā),框架比較簡單婆瓜,多處使用的是接口編程快集,是學習Java不錯的例子
- 難度: 及其簡單,配置一下廉白,寫個解析邏輯个初,整理下保存方法,就OK了
- 輕量: 使用Jsoup做默認的下載器猴蹂,依賴性較低
- 線程: 可自主設置線程數抓取院溺,提高抓取效率
- 重試: 支持失敗重試,次數可以自定義
- 代理: 支持配置代理池磅轻,默認隨機使用代理IP珍逸,也可自定義算法獲取
- 去重: 雙重去重,默認對URL去重聋溜,也可以定義第二層去重邏輯
- 控制: 可自主控制是否需要解析頁面谆膳,減少資源的使用
- 精準: 通過設置URL的正則來精準的解析每一個URL
- 擴展: 幾乎每一個環(huán)節(jié)都可以自定義
使用
使用Maven
在http://search.maven.org上使用最新的版本
在pom中引入
<dependency>
<groupId>com.github.vector4wang</groupId>
<artifactId>vw-crawler</artifactId>
<version>${last.version}</version>
</dependency>
離線使用
可以在項目主頁的release下載最新版本jar,然后導入自己的項目中撮躁。
步驟
- 配置參數
- 抽象正則
- 解析頁面
- 保存數據
各環(huán)節(jié)均支持自定義
示例
抓取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來獲取節(jié)點數據可通過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
抓取了足夠多的數據,我們可以拿數據做很多事冤荆,比如統(tǒng)計各大人才網的職位分布圖
有關ES的可移步這里
最后
輪子造多了就想著造一個模具,代碼寫多了就想寫個框架权纤,一樣的道理钓简。幫助他人乌妒,順便提升自己⊥獾耍框架還有很多需要完善的地方撤蚊,希望使用者多多提issue,也希望大家提PR~~~
源碼
歡迎大家訪問~~~