五、从下载说起

一、下载引擎

爬虫最基本的能力就是发起http请求,下载网页,gecco默认采用httpclient4作为下载引擎。通过实现Downloader接口可以自定义自己的下载引擎,在启动GeccoEngine时需要设置自己的下载引擎。下面的代码不是使用默认的httpclient作为下载引擎,而是使用htmlUnit作为下载引擎。

@Gecco(matchUrl="https://github.com/{user}/{project}", pipelines="consolePipeline", downloader="htmlUnitDownloder")

二、HttpRequest和HttpResponse

HttpRequest表示下载请求,HttpResponse表示下载响应。爬虫下载网页都会模拟浏览器包装成GET或者POST请求,HttpGetRequest和HttpPostRequest分别对应GET和POST请求。
- gecco的请求支持模拟userAgent,并且支持userAgent的随机轮询,在calsspath的根目录下定义userAgents文件,每行表示一个UserAgent; - gecco支持cookie定义,request.addCookie(),可以模拟用户登录; - gecco支持代理服务器的随机轮询,在classpath的根目录下定义proxys文件,每行表示一个代理服务器的主机和端口,如127.0.0.1:8888;

三、下载地址管理

通常爬虫需要一个有效管理下载地址的角色,Scheduler负责下载地址的管理。gecco对初始地址的管理使用StartScheduler,StartScheduler内部采用一个阻塞的FIFO的队列。初始地址通常会派生出很多其他待抓取的地址,派生出来的其他地址采用SpiderScheduler进行管理,SpiderScheduler内部采用线程安全的非阻塞FIFO队列。这种设计使的gecco对初始地址采用了深度遍历的策略,即一个线程抓取完一个初始地址后才会去抓取另外一个初始地址;对初始地址派生出来的地址,采用广度优先策略,派生地址的获取会在下面详细说明。另外,gecco的分布式抓取也是通过Scheduler来完成了,准确的说是通过实现不同的StartScheduler来将初始地址分配到不同的服务器中来完成的。gecco的分布式抓取默认采用redis来实现,具体可以参考gecco-redis项目。

GeccoEngine.create().scheduler(new RedisStartScheduler("127.0.0.1:6379"))

四、初始地址和派生地址

爬虫通常会从若干个初始地址开始爬取网页,爬取下来的网页可能包含其他需要继续抓取的页面,典型的例子是列表页和详情页。列表页作为初始地址,抓取完成后需要针对每个列表项再抓取对应的详情页。gecco派生地址的方式有两种:一种是通过注解@Href(click=true),click为true时,抽取出来的url会继续抓取,如:

@Href(click=true)
@HtmlField(cssPath=".tm-qx-nrBox a")
private String detailUrl;

还一种是显式的加入SpiderScheduler的方法,如:

SchedulerContext.into(currRequest.subRequest("subUrl");

使用@Request注解可以获得当前HttpRequest对象,使用当前request的subRequest方法生成派生地址的请求,这样在相应的pipeline类中即可控制派生请求的增加。

五、多个初始地址的配置

通过在classpath的根目录下放置配置文件starts.json可以配置多个初始地址,如下:

[
    {
        "charset": "GBK",
        "url": "http://item.jd.com/1455427.html"
    },
    {
        "url": "https://github.com/xtuhcy/gecco"
    }
]

六、BeforeDownload和AfterDownload

一些特殊的场景,可能会需要在下载前做下载的预处理和在下载后做特定的处理,之后再传递给pipeline进行处理,这时需要实现BeforeDownload和AfterDownload。如:

@GeccoClass(CruiseDetail.class)
public class CruiseDetailBeforeDownload implements BeforeDownload {
    @Override
    public void process(HttpRequest request) {

    }
}

上面的类针对CruiseDetail这个bean的下载前会做自定义的处理。

@GeccoClass(CruiseRedirect.class)
public class CruiseRedirectAfterDownload implements AfterDownload {

    @Override
    public void process(HttpRequest request, HttpResponse response) {

    }

}

上面这个类会对CruiseRedirect这个bean做下载后的自定义处理。

七、使用httpUnit作为下载引擎

gecco通过扩展downloader实现了对htmlunit的支持。htmlunit是一款开源的java 页面分析工具,读取页面后,可以有效的使用htmlunit分析页面上的内容。项目可以模拟浏览器运行,被誉为java浏览器的开源实现。这个没有界面的浏览器,运行速度也是非常迅速的。htmlunit采用的是rhino作为javascript的解析引擎。

  • 下载

    <dependency>
        <groupId>com.geccocrawler</groupId>
        <artifactId>gecco-htmlunit</artifactId>
        <version>x.x.x</version>
    </dependency>
    
  • 优缺点

使用htmlunit确实能省去很多工作,但是htmlunit也存在很多弊端:

1、效率低下,使用htmlunit后,下载器要将所有js一并下载下来,同时要执行所有js代码,下载一个页面有时需要5~10秒。

2、rhino引擎对js的兼容问题,rhino的兼容性还是存在不少问题的,上述demo就有很多js执行错误。如果大家在抓取时不想看到这些error日志输出可以配置log4j:

log4j.logger.com.gargoylesoftware.htmlunit=OFF

3、使用selenium也可以达到类似目的,selenium本身并不解析js,通过调用不同的浏览器驱动达到模拟浏览器的目的。selenium支持chrome、IE、firefox等多个真实浏览器驱动,也支持htmlunit作为驱动,还支持PhantomJS这种js开发的驱动。

gecco

继续阅读此作者的更多文章