一套簡單的java爬蟲框架VW-Crawler發佈啦!!!

VW-Crawler

Central

背景

自己一直對爬蟲比較感興趣,大學的畢業論文也是一個爬蟲項目(爬教務處信息,然後做了個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~~~

源碼

歡迎大家訪問

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章