Java爬蟲快速開發工具:uncs

零:寫在前面

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

一:基本用法

  • 開發包獲取 目前只能在公司內網maven服務器獲取到

 <dependency>
 <groupId>com.cdc</groupId>
 <artifactId>uncs</artifactId>
 <version>3.0.0.6</version>
 </dependency>
  • 開發單步流程

步驟一

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());
 }
}
  • 服務配置文件

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);

二:源碼url

svn地址:僅供公司內部使用

三:約定

  • crawlId必輸,貫穿整個服務

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

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

四:設計思想

基於流程化的爬蟲開發框架,參數動態可配置化,可擴展。能不讓用戶關心的,就不需要用戶去考慮,屏蔽一切可以屏蔽的細節.

五:配置詳解

5.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時,系統會加載這個標籤的代理服務,詳細參考“代理配置及使用”章節

5.2 part

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

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

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

對應配置文件標籤:uncs:part class--實現類 desc--步驟名稱,不填默認爲類名簡寫

5.3 netCrawlPart

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

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

設置方法內參數HttpCrawlInfo crawlInfo,來改變請求內容

Java爬蟲快速開發工具:uncs


Java爬蟲快速開發工具:uncs


Java爬蟲快速開發工具:uncs


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);
 }
 }
}

5.4 loopPart

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

5.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 {
 }
}

5.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;
 }
 }
 }

5.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());
 }

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

5.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;
 }
}
代理配置方式三:可以在某個步驟單獨使用代理,參考《五-5.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

十:版本升級歷史

詳見《uncs提交歷史.md》 當前最新版本3.0.0.6

十一:未來猜想

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

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

  • 提供快速生成代碼工具

  • 提供可視化工具,隨時查看某個crawlId對應的狀態

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

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

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

十二:fiddler使用說明

1、升級版本到2.3.0.1-SNAPSHOT以上

2、vm參數-Duncs.useFidder=1

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

4、inkeytool.exe -import -file C:Users<Username>DesktopFiddlerRoot.cer -keystore FiddlerKeystore -alias Fiddler

作者:劉鵬飛 宜信技術學院官網:http://college.creditease.cn/#/index


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