一、yield方法
1》作用:调用yield
方法,将请求(request)
发送给Scrapy Engine(引擎)
进行处理
2》参数分析:
yield scrapy.Request( # 该Request对象代表了一个http请求,会经由Downloader去执行,从而产生一个response
url=task["task_url"], # 请求数据库中的url
callback=xxx, # callback回调函数,默认不写会调用parse方法
method='GET', # 请求方法,默认为get
headers=xxx, # 请求头信息(一般在setting.py中的DEFAULT_REQUEST_HEADERS设置即可)
body=xxx, # 请求体
cookies=xxx, # 要携带的cookie信息(一般在middlewares.py中自定义即可)
meta=xxx, # 以字典的格式,向其他方法里面传递信息
encoding='utf-8', # 字符编码
priority=0, # 请求的优先级(数值越低,优先级越高)
dont_filter=False, # 设置请求是否要过滤
errback=self.handle_err, # 当程序处理请求返回有错误时,使用该参数并调用handle_err()函数
)
3》请求方式:
携带的参数相同,如上代码所示。
GET
请求:调用yield scrapy.Request()
方法POST
请求:调用yield scrapy.FormRequest()
方法
二、自定义Downloader中间件
Scrapy 内置的 Downloader Middleware 为 Scrapy 提供了基础的功能,但在项目实战中我们往往需要单独定义 Downloader Middleware 。不用担心,这个过程非常简单,我们只需要实现某几个方法即可。
每个 Downloader Middleware 都定义了一个或多个方法的类,核心的方法有如下三个。
def process_request(self, request, spider)
def process_response(self, request, response, spider)
def process_exception(self, request, exception, spider)
我们只需要实现至少一个方法,就可以定义一个 Downloader Middleware 。下面我们来看看这三个方法的详细用法。
1. def process_request(self, request, spider)
每一个Requests 从引擎传递给下载器之前,该方法被调用。也就是在Request从调度队列里调度出来到Downloader下载执行之前,我们都可以用process_request()
方法对Request进行处理。
而方法的返回值必须为:【None、Response对象、Request对象、或者抛出IgnoreRequest异常】。
process_request()
方法的参数有如下两个。
request
,是Request对象,即被处理的Request。spider
,是Spdier对象,即此Request对应的Spider。
返回类型不同,产生的效果也不同。下面归纳一下不同的返回情况并作出解释:
- 当返回是None时,Scrapy将继续处理该Request,接着执行其他Downloader Middleware的
process_request()
方法,一直到Downloader把Request执行后得到Response才结束。这个过程其实就是修改Request的过程,不同的Downloader Middleware按照设置的优先级顺序依次对Request进行修改,最后送至Downloader执行。 - 当返回为Response对象时,更低优先级的Downloader Middleware的
process_request()
和process_exception()
方法就不会被继续调用,每个Downloader Middleware的process_response()
方法转而被依次调用。调用完毕之后,直接将Response对象发送给Spider来处理。 - 当返回为Request对象时,更低优先级的Downloader Middleware的
process_request()
方法会停止执行。这个Request会重新放到调度队列里,其实它就是一个全新的Request,等待被调度。如果被Scheduler调度了,那么所有的Downloader Middleware的process_request()
方法会被重新按照顺序执行。 - 如果IgnoreRequest异常抛出,则所有的Downloader Middleware的
process_exception()
方法会依次执行。如果没有一个方法处理这个异常,那么Request的errback()
方法就会回调 (即:爬虫文件中的 yield 方法中的 “errback” 参数)。如果该异常还没有被处理,那么它便会被忽略。
2.def process_response(self, request, response, spider)
每一个Response 从下载器返回给引擎之前,该方法被调用。也就是Downloader执行Request下载之后,会得到对应的Response,Scrapy引擎便会将Response发送给Spider进行解析。在发送之前,我们都可以用process_response()
方法来对Response进行处理。
而方法的返回值必须为:【Request对象、Response对象、或者抛出IgnoreRequest异常】。
process_response()
方法的参数有如下三个。
request
,是Request对象,即此Response对应的Request。response
,是Response对象,即此被处理的Response。spider
,是Spider对象,即此Response对应的Spider。
返回类型不同,产生的效果也不同。下面归纳一下不同的返回情况并作出解释:
-
当返回为Request对象时,更低优先级的Downloader Middleware的
process_response()
方法不会继续调用。该Request对象会重新放到调度队列里等待被调度,它相当于一个全新的Request。然后,该Request会被process_request()
方法顺次处理。 -
当返回为Response对象时,更低优先级的Downloader Middleware的
process_response()
方法会继续调用,继续对该Response对象进行处理。 -
如果IgnoreRequest异常抛出,它不会进入到
process_exception()
方法中,而是Request的errback()
方法就会回调 (即:爬虫文件中的 yield 方法中的 “errback” 参数)。如果该异常还没有被处理,那么它便会被忽略。 -
关于
process_response()
方法的使用案例,可参考瓜子案例中的middlewares.py文件:瓜子案例
3.def process_exception(self, request, exception, spider)
当下载器 出现异常 或 下载器中间件的process_request()
方法抛出异常时,例如抛出 “IgnoreRequest” 异常,该方法会被调用。
而方法的返回值必须为:【None、Response对象、Request对象】。
process_exception()
方法的参数有如下三个。
request
,是Request对象,即产生异常的Request。exception
,是Exception对象,即抛出的异常。spdier
,是Spider对象,即Request对应的Spider。
返回类型不同,产生的效果也不同。下面归纳一下不同的返回情况并作出解释:
- 当返回为None时,更低优先级的Downloader Middleware的
process_exception()
会被继续顺次调用,直到所有的方法都被调度完毕。 - 当返回为Response对象时,更低优先级的Downloader Middleware的
process_exception()
方法不再被继续调用,每个Downloader Middleware的process_response()
方法转而被依次调用。 - 当返回为Request对象时,更低优先级的Downloader Middleware的
process_exception()
也不再被继续调用,该Request对象会重新放到调度队列里面等待被调度,它相当于一个全新的Request。然后,该Request又会被process_request()
方法顺次处理。
以上内容便是这三个方法的详细使用逻辑。在使用它们之前,请先对这三个方法的返回值的处理情况有一个清晰的认识。在自定义Downloader Middleware的时候,也一定要注意每个方法的返回类型。
注:以上的中间件方法,只要实现至少一个方法就可以自定义一个Downloader中间件了!!!
- 当需要修改请求头(User_Agent)、设置ip代理时,可以调用中间件的
process_request()方法
;(最终无返回response结果的时候) - 当有出现反爬机制,需要破解反爬时,可以调用中间件的
process_response()方法
;(最终有返回response结果的时候)