Java爬虫快速开发工具:uncs

4次阅读

共计 15056 个字符,预计需要花费 38 分钟才能阅读完成。

零:写在前面
uncs 是 java 快速开发爬虫的工具,简单便捷,经过大量版本迭代和生产验证,可以适用大多数网站,欢迎使用。
一:基本用法
开发包获取目前只能在公司内网 maven 服务器获取到
<dependency>
<groupId>com.cdc</groupId>
<artifactId>uncs</artifactId>
<version>3.0.0.6</version>
</dependency>
开发单步流程
步骤一
java
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, 来改变请求内容

属性名(-)
详细(-)

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);
}
}
}
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、<JDK_Home>binkeytool.exe -import -file C:Users<Username>DesktopFiddlerRoot.cer -keystore FiddlerKeystore -alias Fiddler
作者:刘鹏飞 宜信技术学院官网:http://college.creditease.cn/…

正文完
 0