资讯专栏INFORMATION COLUMN

Java爬虫快速开发工具:uncs

AWang / 2892人阅读

摘要:零写在前面是快速开发爬虫的工具,简单便捷,经过大量版本迭代和生产验证,可以适用大多数网站,欢迎使用。服务最终处理内容,无论成功失败都会执行的步骤。

零:写在前面

uncs是java快速开发爬虫的工具,简单便捷,经过大量版本迭代和生产验证,可以适用大多数网站,欢迎使用。

一:基本用法

开发包获取
目前只能在公司内网maven服务器获取到

     
        com.cdc
        uncs
        3.0.0.6
    

开发单步流程

步骤一

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 {

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

    @Override
    public void afterCrawl(TransContext 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 {

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

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

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

服务配置文件

uncsTestApplicationContext.xml



    
        
            
            
        
    

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 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--步骤名称,不填默认为类名简写
示例:


        
            
        
    

java

package xxx;

import xxx;

/**
 * 加载查询
 */
public class FlowQueryPart extends NetCrawlPart {

    @Override
    public void beforeCrawl(TransContext 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 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,支持根据不同场景走不同分支步骤
场景举例:某网站爬取时,需要根据归属地省份的不同走不同的分支爬取
配置样例:


        
          
            
                
                    
                        
                    
                
                
                    
                        
                    
                
            
        
    

代码样例:

package xxxx;
import xxxx;

public class ChooseKeyTestPart extends ChooseKeyPart {

    @Override
    public boolean isPassPart(TransContext context) {
        // 不需要发送网络请求在这实现
        chooseKey("bj");
        return true;
    }

    @Override
    public void beforeCrawl(TransContext context, HttpCrawlInfo crawlInfo, String crawlId, String mobileType) throws UncsException {
        // 需要发送网络请求来判断的才需要实现
    }

    @Override
    public void afterCrawl(TransContext context, HttpCrawlInfo crawlInfo, String crawlId, String mobileType) throws UncsException {
    }
}
5.6 groupRetryPart

组重试步骤,可以实现整个步骤组重试,可设置最大重试次数,是否重试需要用户根据实际场景调用重试方法。
场景举例:识别图片验证码成功率不是百分百,当失败时需要重新识别,重新验证
配置样例:


        
              
            
                
                    
                
            
        
    

注:重试次数超过最大重试次数时,需要由用户自行判断是否需要抛异常,默认不抛异常,流程正常执行
代码样例:

@Override
    public void afterCrawl(TransContext 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循环,区别在于银行的分支只有下一页,不知道总页数

配置样例:



                
                    
                    
                

代码样例:

    @Override
    public void beforeCrawl(TransContext 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 context, HttpCrawlInfo crawlInfo, String crawlId, String mobileType) throws UncsException {

        // 设置循环最大数次
        this.setComplexLoopMax(context, 5);
        System.out.println(crawlInfo.getHttpCrawlResult());
    }

注:循环内部支持套用任何模板,但是只有循环内所属步骤才能操作循环的属性(最大页数、当前页数),循环内循环的步骤无法跨级操作。

5.8 finalPart

服务最终处理内容,无论成功失败都会执行的步骤。
场景举例:爬取某网站后,为防止对登录状态进行判断,需要在结束后退出登录
配置样例:


        
            
                
                    
                    
                
            
        
        
            
        
    
六:断点

uncs支持程序断点,即支持临时中断正在运行的服务,满足某种场景时,可以重新启动服务,服务会从中断的步骤继续执行。
场景举例:爬取某网站时,有时需要用户输入短信,此时需要人为参与,程序必须中断,等用户输入短信后才可以继续执行
代码示例:
中断代码

@Override
    public void afterCrawl(TransContext 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代理,支持用户自定义代理获取方式,也支持使用系统提供的代理方式,强扩展性。
代理配置方式一:





代理配置方式二:


    
        
    
    
    
        
        
    
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:



    ${log.base}/uncs%d{yyyy-MM-dd}.log
    
        
            ${log.base}/uncs.log.%d{yyyy-MM-dd}.log
        
    
    
        [%level] %date [%thread] - %msg%n
    


    ${log.base}/flow_standard%d{yyyy-MM-dd}.log
    
        
            ${log.base}/flow_standard%d{yyyy-MM-dd}.log
        
    
    
        %date{"yyyy-MM-dd,HH:mm:ss,SSS"}||%msg%n
    



    
    


    
    
九:异步化

提供异步化服务

// 异步启动服务
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、binkeytool.exe -import -file C:UsersDesktopFiddlerRoot.cer -keystore FiddlerKeystore -alias Fiddler

作者:刘鹏飞 宜信技术学院

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73030.html

相关文章

  • Beetl 快速入门

    摘要:简单快速了解是前端视图填充数据的工具,是个页面模板,可以像表达式那样操作数据,那样公共代码引用,很多好用的方法。目录结构快速接入深入了解待续。。。 简单快速了解 Beetl 是前端视图填充数据的工具,是个页面模板,可以像 el 表达式那样操作数据,jsp 那样公共代码引用,很多好用的方法。官方模板对比:showImg(https://segmentfault.com/img/bVbfa...

    wushuiyong 评论0 收藏0
  • 当年玩耍httpclient

    摘要:当年玩耍前言是开发中最常用的工具之一,通常大家会使用去调用远程,使用其中比较基础的,长期开发爬虫,会接触不常用的,同时会遇到各式各样的坑,下面会总结这些年遇到的坑坑坑坑一解决过程开发某省份移动爬虫时,加载首页会报标题错误,尝试各种办法都不好 当年玩耍httpclient 前言 httpclient是java开发中最常用的工具之一,通常大家会使用httpcilent去调用远程,使用其中比...

    lykops 评论0 收藏0
  • 【微信小程序爬虫】表情包小程序图文视频教学,从零写起,保姆教程!!!

    摘要:文章目录前言爬取分析视频教学成果展示福利入门到就业学习路线规划小白快速入门爬虫路线前言皮皮虾一个沙雕而又有趣的憨憨少年,和大多数小伙伴们一样喜欢听歌游戏,当然除此之外还有写作的兴趣,,日子还很长,让我们一起加油努力叭话 ...

    coordinate35 评论0 收藏0
  • python模块之os.path

    摘要:返回的绝对路径名返回文件名,等同于调用返回值的第二个元素。与不同,此函数的返回值一定是一个有效路径。返回值是自时间算起的浮点值,单位为秒。规范路径名中的多余分隔符以及上级引用,如将全部转换为。 os.path.abspath(path) 返回path的绝对路径名 >>> os.path.abspath(.) C:UsersadminDesktopPycharmProjectspytho...

    mrli2016 评论0 收藏0
  • 从零开始写爬虫

    摘要:几个朋友对爬虫很感兴趣,他们也都是开发人员,一个开发两个开发,都没有过项目开发经验,正好其中一个最近要爬一个网店的产品信息,所以希望我能拿这网站当写一个爬虫来给他们参考学习。我们就在这个文件里开发爬虫的相关逻辑。 几个朋友对爬虫很感兴趣,他们也都是开发人员,一个PHP开发两个JAVA开发,都没有过python项目开发经验,正好其中一个最近要爬一个网店的产品信息,所以希望我能拿这网站当d...

    wwq0327 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<