WebCollector 2.72处理301/302重定向、404 Not Found等Http状态

官网地址:https://github.com/CrawlScript/WebCollector

WebCollector的Http请求结果有两种状态:请求成功和请求失败。这两种状态的定义如下:

  • 请求成功:服务器成功地返回了请求URL的状态及数据。这里注意,不是状态码200才叫请求成功,一般情况下,301/302/404都可能对应请求成功。例如对于404,服务器正确地告诉了你,当前的URL不存在;对于301/302,服务器正确地告诉了你,当前的URL需要重定向,并且会在Http头中用Location头告诉你重定向的URL。服务器正确地响应了你的请求,我们都认为是请求成功,不需要重新请求(因为重新请求获得的还是同样的信息)。
  • 请求失败:非请求成功的状态。如请求超时、因为反爬虫机制而产生的403、因为反爬虫机制产生的302(重定向到验证码页面)等,这些情况需要通过重新请求来获得正确地响应。

WebCollector默认使用OkHttpRequester作为Http请求插件(Requester插件)。可以通过下面的代码查看OkHttpRequester认为请求成功地状态码集合:

public static void main(String[] args) {
    OkHttpRequester requester = new OkHttpRequester();
    System.out.println(requester.getSuccessCodeSet());
}

执行结果如下,可以看到,OkHttpRequester默认会将404、200、301、302都认为是访问成功:

[404, 200, 301, 302]

这里要注意,OkHttpRequester在遇到301和302时并不会自动跳转,也不建议在Http请求插件中定制自动跳转功能。建议在visit中处理,处理跳转方法如下:

@Override
public void visit(Page page, CrawlDatums next) {
    // 如果遇到301或者302,手动跳转(将任务加到next中)
    // 并且复制任务的meta
    if(page.code() == 301 || page.code() == 302){
        next.addAndReturn(page.location()).meta(page.meta());
        return;
    }
}

上面的处理方法利用page.location()方法获取Http头中的Location头(重定向URL),并将其作为一个新的任务加到next中。任务的meta(附加信息)也需要被复制到新的任务中。之所以这样设计,是因为很多采用自动跳转的爬虫框架会导致重复的采集,例如访问http://a.com和http://b.com都会重定向到http://c.com,对于一些采用自动去重机制的框架,可能会有如下的采集流程。在下面的流程中,http://c.com页面上的数据被重复采集了。

错误的重定向处理方式:
1. 检查http://a.com是否被访问,发现未被访问
2. 访问http://a.com,自动重定向到http://c.com,获取数据,记录http://a.com已被采集(注意这里可能不会记录http://c.com被访问)
3. 检查http://b.com是否被访问,发现未被访问
4. 访问http://b.com,自动重定向到http://c.com,获取数据,记录http://b.com已被采集(注意这里可能不会记录http://c.com被访问)

但是如果按照上面推荐的方法,即不在Requester中自动跳转,而是在visit中处理重定向,就不会出现这个问题。虽然爬虫会向next(后续任务)中添加两次http://c.com,但是爬虫是有自动去重机制的,重复的任务是会被去重的。最核心的原因是,如果不在Requester插件中自动进行跳转,一个URL可以与服务器上的响应一一对应,而不会出现上面错误的方法中,两个URL对应同一个响应(经过自动重定向,响应都是http://c.com)。

对于一些特殊的情况,我们需要将301或者302设置为请求失败,例如采集搜狗微信时,301或302可能是你出发了反爬虫验证码,会重定向到验证码页面,这种情况需要将其认为是请求失败,通过重新请求(可能使用新的代理)来获得正确地响应,可以通过下面的代码将301和302设置为请求失败:

public static void main(String[] args) {
    OkHttpRequester requester = new OkHttpRequester();
    requester.removeSuccessCode(301);
    requester.removeSuccessCode(302);
    System.out.println(requester.getSuccessCodeSet());
}

 运行结果如下,可以看到成功状态码列表中已经没有了301和302:

[404, 200]

如果希望将一些Http状态码设置为请求成功(如304),可以通过下面的代码:

public static void main(String[] args) {
    OkHttpRequester requester = new OkHttpRequester();
    requester.addSuccessCode(304);
    System.out.println(requester.getSuccessCodeSet());
}

运行结果如下:

[304, 404, 200, 301, 302]

 

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页