Java爬蟲快速開發工具uncs的部署攻略

宜信技術發表於2019-05-30

寫在前面

uncs是java快速開發爬蟲的工具,簡單便捷,經過大量版本迭代和生產驗證,可以適用大多數網站,推薦使用。

一、基本用法

1.1 開發包獲取

目前只能在公司內網maven伺服器獲取到

  <dependency>
        <groupId>com.cdc</groupId>
        <artifactId>uncs</artifactId>
        <version>3.0.0.6</version>
    </dependency>

 

1.2 開發單步流程

步驟一

package com.cdc.uncs.service.parts;

import com.cdc.uncs.exception.UncsException;
import com.cdc.uncs.model.HttpCrawlInfo;
import com.cdc.uncs.model.TestRequest;
import com.cdc.uncs.model.TestResponse;
import com.cdc.uncs.service.NetCrawlPart;
import com.cdc.uncs.service.TransContext;

public class NetCrawlTestPart extends NetCrawlPart<TestRequest, TestResponse> {

    @Override
    public void beforeCrawl(TransContext<TestRequest, TestResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String type) throws UncsException {
        String url = "http://www.baidu.com";
        crawlInfo.setUrl(url);
    }

    @Override
    public void afterCrawl(TransContext<TestRequest, TestResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String type) throws UncsException {
        System.out.println(crawlInfo.getHttpCrawlResult());
    }
}

 

步驟二

package com.cdc.uncs.service.parts;
import com.cdc.uncs.exception.UncsException;
import com.cdc.uncs.model.HttpCrawlInfo;
import com.cdc.uncs.model.TestRequest;
import com.cdc.uncs.model.TestResponse;
import com.cdc.uncs.service.NetCrawlPart;
import com.cdc.uncs.service.TransContext;

public class NetCrawlTestPart2 extends NetCrawlPart<TestRequest, TestResponse> {

    @Override
    public void beforeCrawl(TransContext<TestRequest, TestResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String type) throws UncsException {

        String url = "http://www.hao123.com";
        crawlInfo.setUrl(url);
    }

    @Override
    public void afterCrawl(TransContext<TestRequest, TestResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String type) throws UncsException {
        System.out.println(crawlInfo.getHttpCrawlResult());
    }
}

1.3 服務配置檔案

uncsTestApplicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://uncs.cdc.com/schema/uncs http://uncs.cdc.com/schema/uncs/springuncs.xsd"
       xmlns:uncs="http://uncs.cdc.com/schema/uncs"
       default-autowire="byName">
    <uncs:crawl id="testService" browser="Chrome51" poolSize="5" proxyType="no">
        <uncs:list>
            <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart" desc="登陸"/>
            <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart2" desc="獲取"/>
        </uncs:list>
    </uncs:crawl>
</beans>
demo樣例

        // ----------------------系統啟動---------------------------
        // 使用者自定義的服務配置檔案
        String xmlTest = "classpath*:uncsTestApplicationContext.xml";
        // 啟動uncs的初始化引數   redis:ip、port socks5:ip、port 專案縮寫 http代理 獲取http代理超時時間 代理型別
        InitParam param = new InitParam("127.0.0.1", 6379, "ss5.xx.com", 1080, "ct", "http://xxx", 3000, "no");
        // 啟動uncs  param:啟動引數  xmlTest...:服務配置檔案,可以是多個
        UncsLancher.startUp(param, xmlTest);

        // ----------------------呼叫服務--------------------------
        // 定義上下文,貫穿整個服務
        TransContext<TestRequest, TestResponse> transContext = TransContext.newInstance(TestRequest.class, TestResponse.class);
        // crawlId:單個爬取交易的唯一索引
        String crawlId = Long.toString(System.currentTimeMillis());
        // type:交易的型別,輔助引數,使用者自定義。例如爬取時可以把型別作為type,可以貫穿整個交易
        String type = "xxx";
        transContext.setCrawlId(crawlId);
        transContext.setType(type);
        // 服務名稱,對應配置檔案中uncs:crawl標籤的id
        String serverName = "testService";
        // 開始執行交易
        TestResponse response = UncsService.startService(serverName, transContext);

二、約定

  • crawlId必輸,貫穿整個服務

  • 流程內的步驟實現類必須繼承相關父類

  • 暫時必須使用redis為框架提供支援,以後會開發不需要redis的單機版本

三、設計思想

基於流程化的爬蟲開發框架,引數動態可配置化,可擴充套件。能不讓使用者關心的,就不需要使用者去考慮,遮蔽一切可以遮蔽的細節.

四、配置詳解

4.1 crawl交易配置

uncs:crawl標籤

attr:

  • id:唯一服務名,例:testService

  • browser:瀏覽器型別,列舉:Chrome51(chrome瀏覽器),IE9,IE8,FIREFOX,DEFAULT,預設是chrome瀏覽器,設定這個屬性,程式碼就不需要設定http header的user-agent了

  • poolSize:服務執行時執行緒池大小即這個服務支援的併發大小,如果不設定,則使用公共的執行緒池

  • proxyType:代理型別,no-不使用代理 http:使用http代理 socks:socks5代理 default-http:預設的http代理 default-socks:預設的socks代理 (兩個預設的代理型別在初始化引數InitParam設定)

property:

uncs:list--流程列表,服務按順序執行配置的實現類列表,list內支援所有型別的part

uncs:finalPart--流程完成後,不管成功還是失敗,都會執行的步驟

uncs:proxyService--擴充套件的代理服務,使用者可以自定義bean,來編寫自己的代理服務,當uncs:crawl的attr-proxyType設定為http或socks時,系統會載入這個標籤的代理服務,詳細參考“代理配置及使用”章節

4.2 part

所有模板步驟的父類,空模板,可以自由發揮

步驟:建立java類-->繼承com.cdc.uncs.service.Part-->重寫work方法-->配置檔案

當這個步驟可能不需要執行時,重新isPassPart方法,返回true即跳過,所有子類别範本都有這個步驟

對應配置檔案標籤:uncs:part class--實現類 desc--步驟名稱,不填預設為類名簡寫

4.3 netCrawlPart

網路爬取步驟模板,使用者使用此模板就不用關心httpclient如何使用了

步驟:建立java類-->繼承com.cdc.uncs.service.NetCrawlPart-->重寫beforeCrawl和afterCrawl方法-->配置檔案 beforeCrawl:爬取前組裝http請求引數

設定方法內引數HttpCrawlInfo crawlInfo,來改變請求內容

屬性名(一)詳細(一)
method post/get
mineType img-圖片 json-暫不支援 html-文字
httpParamType form-表單 string-純字串
url 爬取的url
referer 來源頁
charset 編碼,預設是utf-8
isRelocal 是否自動跳轉
params 表單引數
stringParam 當httpParamType為string時,才生效
headerParam http header引數,支援Map方法和一個一個設定的方法,常用的header支援便捷設定方法,user-agent可以不設定,cookie不需要設定
httpCrawlResult/httpCrawlImgResult 用於儲存返回結果
cookies 可以手工設定cookie
relocalList 當isRelocal為true時,頁面跳轉流程會在這儲存
proxyService 可以單獨某個步驟設定代理
isNetErrThrow 發生網路錯誤時,是否丟擲異常,預設不拋
isLogResponse 是否記錄返回日誌
e 真正的異常物件
timeOut 單步超時時間
isJdkSafe 是否支援jdk1.7安全策略
tempInfo 臨時引數,使用者部分http互動引數設定
tempInfo.usedProxy 但步驟代理策略
tempInfo.responseCode http返回碼
tempInfo.proxyParam 代理服務的引數
tempInfo.httpRetryMaxTimes 失敗後最大的重試次數
tempInfo.sslVersion 指定ssl協議版本號
tempInfo.clearCookie 是否清空cookie
tempInfo.poolEntityAliveTime http池化,每個連結存活時間
tempInfo.poolSize http池化,池大小
afterCrawl:爬取後解析返回結果

HttpCrawlInfo crawlInfo.getHttpCrawlResult和getHttpCrawlImgResult獲取返回結果

對應配置檔案標籤,uncs:netCrawlPart,class--實現類 desc--步驟名稱,不填預設為類名簡寫 示例:

<uncs:crawl id="testService" browser="Chrome51" poolSize="5" proxyType="no">
        <uncs:list>
            <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart" desc="網路爬取測試步驟"/>
        </uncs:list>
    </uncs:crawl>
 

java

package xxx;

import xxx;

/**
 * 載入查詢
 */
public class FlowQueryPart extends NetCrawlPart<FlowGetterRequest, FlowGetterResponse> {

    @Override
    public void beforeCrawl(TransContext<FlowGetterRequest, FlowGetterResponse> context, HttpCrawlInfo crawlInfo, String s, String s1) throws UncsException {
        String url = (String) context.getTempParamValue(ParamKey.XXX);
        String referer = (String) context.getTempParamValue(ParamKey.REFXXX);
        
        crawlInfo.addAccept("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        crawlInfo.addAcceptEncoding("gzip, deflate, sdch");
        crawlInfo.addAcceptLanguage("zh-CN,zh;q=0.8");
        crawlInfo.addConnection("keep-alive");
        crawlInfo.addHost("XXX.com");

        crawlInfo.addParam("query", "true");
        crawlInfo.addParam("q_from_date",  (String) context.getTempParamValue(ParamKey.BEGIN_DATE));
        crawlInfo.addParam("q_to_date", (String) context.getTempParamValue(ParamKey.END_DATE));

        crawlInfo.setCharset(CoreConstant.CHARSET);
        crawlInfo.setMineType(MineType.HTML);
        crawlInfo.setMethod(HttpMethod.GET);
        crawlInfo.setUrl(url);
        crawlInfo.setReferer(referer);

        context.addTempParam(ParamKey.NEXT_REFERER, url);

    }

    @Override
    public void afterCrawl(TransContext<FlowGetterRequest, FlowGetterResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String bankCode) throws UncsException {
        String result = crawlInfo.getHttpCrawlResult();
        if(Strings.isNullOrEmpty(result)) {
            throw new SystemUncsException("網頁載入錯誤", ErrorCode.XXX);
        }
    }
}

4.4 loopPart

迴圈步驟模板,已經過時的模板,被complexLoopPart複雜迴圈步驟模板替換,不再維護,可以使用,可能存在一些BUG,只支援單步驟迴圈

4.5 switchPart

選擇步驟模板,類似java的switch,支援根據不同場景走不同分支步驟 場景舉例:某網站爬取時,需要根據歸屬地省份的不同走不同的分支爬取 配置樣例:

<uncs:crawl id="testService" browser="Chrome51" poolSize="5" proxyType="no">
        <uncs:list>
          <!-- choosePartClass必須繼承com.cdc.uncs.service.ChooseKeyPart -->
            <uncs:switchPart choosePartClass="com.cdc.uncs.service.parts.ChooseKeyTestPart" choosePartDesc="選擇key測試步驟">
                <uncs:entity key="bj">
                    <uncs:list>
                        <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart" desc="北京"/>
                    </uncs:list>
                </uncs:entity>
                <uncs:entity key="sh">
                    <uncs:list>
                        <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart2" desc="上海"/>
                    </uncs:list>
                </uncs:entity>
            </uncs:switchPart>
        </uncs:list>
    </uncs:crawl>
 

程式碼樣例:

package xxxx;
import xxxx;

public class ChooseKeyTestPart extends ChooseKeyPart<TestRequest, TestResponse> {

    @Override
    public boolean isPassPart(TransContext<TestRequest, TestResponse> context) {
        // 不需要傳送網路請求在這實現
        chooseKey("bj");
        return true;
    }

    @Override
    public void beforeCrawl(TransContext<TestRequest, TestResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String mobileType) throws UncsException {
        // 需要傳送網路請求來判斷的才需要實現
    }

    @Override
    public void afterCrawl(TransContext<TestRequest, TestResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String mobileType) throws UncsException {
    }
}
 

4.6 groupRetryPart

組重試步驟,可以實現整個步驟組重試,可設定最大重試次數,是否重試需要使用者根據實際場景呼叫重試方法。 場景舉例:識別圖片驗證碼成功率不是百分百,當失敗時需要重新識別,重新驗證 配置樣例:

<uncs:crawl id="testService" browser="Chrome51" poolSize="5" proxyType="no">
        <uncs:list>
              <!-- betweenMillis重試間隔時間(毫秒) maxRetryTimes最大重試次數 -->
            <uncs:groupRetryPart betweenMillis="10" maxRetryTimes="5">
                <uncs:list>
                    <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart" desc="網路爬取測試步驟"/>
                </uncs:list>
            </uncs:groupRetryPart>
        </uncs:list>
    </uncs:crawl>

 

注:重試次數超過最大重試次數時,需要由使用者自行判斷是否需要拋異常,預設不拋異常,流程正常執行 程式碼樣例:

@Override
    public void afterCrawl(TransContext<FlowGetterRequest, FlowGetterResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String bankCode) throws UncsException {

        String result = crawlInfo.getHttpCrawlResult();
        if(Strings.isNullOrEmpty(result)) {
            throw new SystemUncsException("網頁載入錯誤", ErrorCode.ERROR_3006);
        }
        // 校驗結果
        try {
            CCBBaseUtil.validateResult(result, crawlId, bankCode, this.getName(), log);
        } catch (UncsException e) {
            String code = e.getCode();
            if(ErrorCode.ERROR_0000.equals(code)) {
                // 驗證碼錯誤,重試
                // 驗證重試次數
                if(this.getGroupRetryCurrent(context) < this.getGroupRetryMax(context)) {
                    // 重試
                    retry();
                }else{
                    log.log(crawlId, this.getName(), bankCode, "圖片驗證碼超過最大重試次數");
                    throw new SystemUncsException("圖片驗證碼錯誤次數超限,請重試,並檢查", ErrorCode.ERROR_2002);
                }
            } else {
                throw e;
            }
        }
    }

 

4.7 complexLoopPart

複雜迴圈步驟模板,類似java的迴圈,即支援for迴圈也支援while迴圈,預設是for迴圈,支援任何模板套用。 新增支援迴圈橫向併發 場景舉例: for迴圈,爬取某網站資料時,按月份迴圈爬取為第一層迴圈,每個月型別的分頁為第二層迴圈 while迴圈,同for迴圈,區別在於銀行的分支只有下一頁,不知道總頁數 配置樣例:

<!-- loopType 迴圈型別 for/while 不填預設for  preClass前置處理類,必須繼承com.cdc.uncs.service.LoopPrePart,一般用做查詢和設定最大迴圈次數,當然也可以在內部步驟內設定  isAsyn是否併發 asynThreadCount併發最大執行緒數 -->
<uncs:complexLoopPart loopType="for" preClass="" preDesc="" isAsyn="false" asynThreadCount="5">
                <uncs:list>
                    <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart" desc="複雜迴圈步驟"/>
                    <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart2" desc="複雜迴圈步驟2"/>
                </uncs:list>
</uncs:complexLoopPart>
 

程式碼樣例:

@Override
    public void beforeCrawl(TransContext<TestRequest, TestResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String mobileType) throws UncsException {

        // 獲取當前迴圈次數
        this.getComplexLoopCurrent(context);
        getCookieValue(crawlId, "BAIDUID");
        String url = "http://www.baidu.com";
        crawlInfo.setUrl(url);
    }

    @Override
    public void afterCrawl(TransContext<TestRequest, TestResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String mobileType) throws UncsException {

        // 設定迴圈最大數次
        this.setComplexLoopMax(context, 5);
        System.out.println(crawlInfo.getHttpCrawlResult());
    }

 

注:迴圈內部支援套用任何模板,但是隻有迴圈內所屬步驟才能操作迴圈的屬性(最大頁數、當前頁數),迴圈內迴圈的步驟無法跨級操作。

4.8 finalPart

服務最終處理內容,無論成功失敗都會執行的步驟。 場景舉例:爬取某網站後,為防止對登入狀態進行判斷,需要在結束後退出登入 配置樣例:

<uncs:crawl id="testService" browser="Chrome51" poolSize="5" proxyType="no">
        <uncs:list>
            <uncs:complexLoopPart loopType="for" preClass="" preDesc="">
                <uncs:list>
                    <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart" desc="複雜迴圈步驟"/>
                    <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart2" desc="複雜迴圈步驟2"/>
                </uncs:list>
            </uncs:complexLoopPart>
        </uncs:list>
        <uncs:finalPart>
            <uncs:part class="com.cdc.uncs.service.parts.NetCrawlTestPart" desc="退出"/>
        </uncs:finalPart>
    </uncs:crawl>

 

五、斷點

uncs支援程式斷點,即支援臨時中斷正在執行的服務,滿足某種場景時,可以重新啟動服務,服務會從中斷的步驟繼續執行。 場景舉例:爬取某網站時,有時需要使用者輸入簡訊,此時需要人為參與,程式必須中斷,等使用者輸入簡訊後才可以繼續執行 程式碼示例: 中斷程式碼

@Override
    public void afterCrawl(TransContext<TestRequest, TestResponse> context, HttpCrawlInfo crawlInfo, String crawlId, String mobileType) throws UncsException {
        // 中斷一下
        this.pauseNeedMsg();
        System.out.println(crawlInfo.getHttpCrawlResult());
    }

 

重新啟動服務

// 重新啟動服務
        String msgCode = "123456";
        TestResponse response1 = UncsService.restartService(crawlId, msgCode, null, TestResponse.class);

 

六、代理配置及使用

uncs支援http代理和socks5代理,支援使用者自定義代理獲取方式,也支援使用系統提供的代理方式,強擴充套件性。 代理配置方式一:

<!-- 預設的http代理 -->
<uncs:crawl id="testService" browser="Chrome51" poolSize="5" proxyType="default-http">
<!-- 預設的socks代理 -->
<uncs:crawl id="testService" browser="Chrome51" poolSize="5" proxyType="default-socks">
<!-- 系統啟動時,設定預設的兩種代理方式及全域性代理方式
InitParam param = new InitParam("127.0.0.1", 6379, "ss5.xxx", 1080, "ct", "http://xxxx", 3000, "no");-->

 

代理配置方式二:

<uncs:crawl id="testService" browser="Chrome51" poolSize="5" proxyType="http">
    <uncs:list>
        <uncs:netCrawlPart class="com.cdc.uncs.service.parts.NetCrawlTestPart" desc="步驟"/>
    </uncs:list>
    <!-- 實現類必須繼承對應的類 com.cdc.uncs.http.IHttpProxy或com.cdc.uncs.http.ISocksProxy -->
    <uncs:proxyService class="com.cdc.uncs.http.impl.TestHttpProxy">
        <uncs:property name="ip" value="127.0.0.1"/>
        <uncs:property name="testxxxxx" value=""/>
    </uncs:proxyService>
</uncs:crawl>
package com.cdc.uncs.http.impl;

import com.cdc.uncs.http.IHttpProxy;
import com.cdc.uncs.http.ISocksProxy;
import com.cdc.uncs.util.HttpGreenHelper;
import org.apache.http.HttpHost;

import java.util.HashMap;
import java.util.Map;

/**
 * 預設http代理
 */
public class TestHttpProxy extends IHttpProxy {
    private String ip;
    private Object testxxxxx;
    public TestHttpProxy() {
    }

    /**
     * 獲取crawlId
     *
     * @param cid           唯一標識
     * @param type          型別
     * @param logServerName 日誌標識
     * @return
     */
    @Override
    public HttpHost getProxy(String cid, String type, String logServerName) {
        return new HttpHost(ip, 8888);
    }
    public String getIp() {
        return ip;
    }
    public void setIp(String ip) {
        this.ip = ip;
    }
    public Object getTestxxxxx() {
        return testxxxxx;
    }
    public void setTestxxxxx(Object testxxxxx) {
        this.testxxxxx = testxxxxx;
    }
}

 

代理配置方式三:可以在某個步驟單獨使用代理,參考《四-4.2 netCrawlPart》

七、日誌配置及使用

uncs使用固定日誌名,分為標準日誌和uncs日誌,標準日誌是日誌搜尋系統要求的格式輸出,可以忽略,uncs日誌表示業務日誌 logback:

<property name="log.base" value="D:/log/uncslog" />
<appender name="uncslog" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <fileNamePattern>${log.base}/uncs%d{yyyy-MM-dd}.log</fileNamePattern>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <FileNamePattern>
            ${log.base}/uncs.log.%d{yyyy-MM-dd}.log
        </FileNamePattern>
    </rollingPolicy>
    <layout class="ch.qos.logback.classic.PatternLayout">
        <pattern>[%level] %date [%thread] - %msg%n</pattern>
    </layout>
</appender>
<appender name="standardlog" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <fileNamePattern>${log.base}/flow_standard%d{yyyy-MM-dd}.log</fileNamePattern>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <FileNamePattern>
            ${log.base}/flow_standard%d{yyyy-MM-dd}.log
        </FileNamePattern>
    </rollingPolicy>
    <layout class="ch.qos.logback.classic.PatternLayout">
        <pattern>%date{"yyyy-MM-dd,HH:mm:ss,SSS"}||%msg%n</pattern>
    </layout>
</appender>
<!-- 標準日誌 -->
<logger name="standard" additivity="false">
    <level value="DEBUG" />
    <appender-ref ref="standardlog" />
</logger>
<logger name="com.cdc.uncs" additivity="false">
    <level value="DEBUG" />
    <appender-ref ref="uncslog" />
</logger>

 

八、非同步化

提供非同步化服務

// 非同步啟動服務
UncsService.ayncStartService
// 獲取當前服務狀態
UncsService.getResponse

 

九、未來猜想

優化程式碼質量,完善http初始化部分程式碼(優化完畢)及cookie處理部分程式碼(完成)

讓part持有context,這樣部分方法不再需要context引數(完成)

提供快速生成程式碼工具

提供視覺化工具,隨時檢視某個crawlId對應的狀態

整合各大優秀的爬蟲框架,形成對應模板

提供單機模式,可以選擇不使用redis,本地儲存

提供併發步驟模板,用於提高速度(完成)

十、fiddler使用說明

升級版本到2.3.0.1-SNAPSHOT以上

vm引數-Duncs.useFidder=1

fiddler配置 tools->fiddler options->https->actions->export root certificate to ...

\bin\keytool.exe -import -file C:\Users\Desktop\FiddlerRoot.cer -keystore FiddlerKeystore -alias Fiddler

 

作者:劉鵬飛

來源:宜信技術學院

相關文章