scrapy middlewares process_request/response不同返回值的分析

  最近学习scrapy爬虫框架,领略到中间件的强大作用,随机设置UA、设置代理、对接selenium等,但是对于process_request以及process_response的返回值和他们的作用不是很理解,网上的解释也十分笼统,如下截屏:
scrapy middlewares process_request/response不同返回值的分析
今天我做了一个相关的测试,详细看看不同返回值scrapy是如何处理的。
主函数如下:
scrapy middlewares process_request/response不同返回值的分析

process_request

- 返回None
代码如下:
scrapy middlewares process_request/response不同返回值的分析
结果如下:
scrapy middlewares process_request/response不同返回值的分析
可以看到,打印了这是第一次请求,并且输出了百度的官网源代码,程序与我们想的一样,process_response打印源码并且返回给引擎,然后可以调用parse函数对其进行提取数据。

- 返回Request
代码如下:
scrapy middlewares process_request/response不同返回值的分析
记得返回request的时候需要把dont_filter=True加上,不然scrapy会自动过滤掉已经请求过的网页。效果如下:
scrapy middlewares process_request/response不同返回值的分析
程序会陷入死循环,因为返回request的话,程序会立刻停止下面的工作,立马重新去把这个request加入队列,然后继续处理它,也就是重新让process_request处理它,不幸的是,我们一直返回request,并且dont_filter=True,所以程序进入死循环,不会执行到proces_response,自然也就不会打印出源码。
注意,返回request的时候,新的request会立马给调度器重新发送请求,而不是之后在重新发送请求。如下所示,
start_urls = ['https://www.baidu.com','https://www.jianshu.com','https://www.tencent.com']
scrapy middlewares process_request/response不同返回值的分析

结果如下:
scrapy middlewares process_request/response不同返回值的分析

看到,第一次请求的时候,在process_request的时候,我们打印输出一次,接着返回request,调度器立刻再次发送该请求,所以在process_request又打印了一边,然后在返回request的时候,因为这次的url和之前相同,所以就不再处理的返回request了,该request也不会经过下载器到达process_response,所以一次’ * ‘也没有打印,调度器从url队列获取下一个request。

- 返回Response
代码如下:

scrapy middlewares process_request/response不同返回值的分析
输出如下:
scrapy middlewares process_request/response不同返回值的分析
奇怪,为什么没有打印出网页源代码,反而输出这段文字,这就是因为我们返回了一个response,并且自定义了body字段,返回Response以后,结果会直接返回给引擎,而不经过下载器处理了。我们来看看scrapy.http.Response的参数,
scrapy middlewares process_request/response不同返回值的分析
看出,我们在返回response时,可以传递status、body、headers等参数,这里要注意body中的数据必须使byte类型,而不是str。在使用selenium抓取数据时,大多返回response,并且使body=browser.page_source这样就可以获取渲染过的网页的源代码,而不是交给下载器下载,因为那样得到的网页源代码得不到经过ajax处理的数据。

Process_response

  • 返回Response
    scrapy middlewares process_request/response不同返回值的分析
    scrapy middlewares process_request/response不同返回值的分析
    结果如下
    scrapy middlewares process_request/response不同返回值的分析
    这里的response与上面request的完全相同。可以发现,我们在process_response修改了网页源代码,然后主函数parse打印了response信息,发现响应的url和内容已经被我们更改了。

- 返回Request
代码如下:
scrapy middlewares process_request/response不同返回值的分析
结果如下:
scrapy middlewares process_request/response不同返回值的分析
程序还是陷入了死循环,因为当请求经过process_request,打印了请求的次数以后,又经过process_response,打印了20个‘*’后又返回request,这时候会将新的request重新给调度器,然后再次发送这个请求给process_request处理,这样,就会一直死循环下去。

总结
  在处理process_request,一般是返回None,如果使用selenimu,则返回response,谨慎返回request,在处理process_response,一般返回response,谨慎返回request。
  scrapy是一个很强大的框架,在这个框架之上我们可以扩展许多功能,使得爬取数据的能力更上一层楼,当然,这些是要在理解基本爬虫原理和熟悉相关库的使用,比如requests、selenium和xpath等,以及大量实战练习之后才能掌握的。
  希望以上的内容对小伙伴理解scrapy有所帮助,欢迎讨论。