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复制代码
作者:刘鹏飞       宜信技术学院官网:http://college.creditease.cn/#/index复制代码


猜你喜欢

转载自juejin.im/post/5c3d84c1e51d455244741784