1. 程式人生 > >一套簡單的java爬蟲框架VW-Crawler釋出啦!!!

一套簡單的java爬蟲框架VW-Crawler釋出啦!!!

VW-Crawler

Central

背景

自己一直對爬蟲比較感興趣,大學的畢業論文也是一個爬蟲專案(爬教務處資訊,然後做了個Android版教務管理系統,還獲得了優秀畢業設計的稱號),自那以後遇到自己感興趣的網站就會去抓一下。前段時間工作上需要一些JD資訊,我就從網上找了個開源的爬蟲框架WebMagic,使用簡單,易配置,功能也很強大,當然了也有些網站的資料不適合使用。前前後後寫了不下十幾個,慢慢的就想是不是可以把這些爬蟲程式碼再抽象出來,做出一個簡易的爬蟲框架呢?於是就嘗試去看WebMagic的原始碼,後來又發現了一個原始碼比較容易解讀的爬蟲框架XXL-CRAWLER,簡單的分析了原始碼之後,開發自己一套爬蟲框架的慾望更加強烈,於是在2017年底的時候就開始了開發,中間斷斷續續得停了寫,寫了停。直到最近8月底的時候才算出了一個版本,然後順勢把它放到了Maven公服倉庫上。一個人的力量很薄弱,要想完善這個爬蟲的健壯性、可用性和易擴充套件性還需要大家的力量!

特點

  • 語言: Java開發,框架比較簡單,多處使用的是介面程式設計,是學習Java不錯的例子
  • 難度: 及其簡單,配置一下,寫個解析邏輯,整理下儲存方法,就OK了
  • 輕量: 使用Jsoup做預設的下載器,依賴性較低
  • 執行緒: 可自主設定執行緒數抓取,提高抓取效率
  • 重試: 支援失敗重試,次數可以自定義
  • 代理: 支援配置代理池,預設隨機使用代理IP,也可自定義演算法獲取
  • 去重: 雙重去重,預設對URL去重,也可以定義第二層去重邏輯
  • 控制: 可自主控制是否需要解析頁面,減少資源的使用
  • 精準: 通過設定URL的正則來精準的解析每一個URL
  • 擴充套件: 幾乎每一個環節都可以自定義

使用

使用Maven

<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~~~

原始碼

歡迎大家訪問