Downloader Middleware 的用法
Downloader Middleware 即下载中间件,它是处于 Scrapy 的 Request 和 Response 之间的处理模块。
Scheduler 从队列中拿出一个 Request 发送给 Downloader 执行下载,这个过程会经过 Downloader Middleware 的处理。另外,当 Downloader 将 Request 下载完成得到 Response 返回给 Spider 时会再次经过 Downloader Middleware 处理。
也就是说,Downloader Middleware 在整个架构中起作用的位置是以下两个:
·在 Scheduler 调度出队列的 Request 发送给 Downloader 下载之前,也就是我们可以在 Request 执行下载之前对其进行修改。
·在下载后生成的 Response 发送给 Spider 之前,也就是我们可以在生成 Resposne 被 Spider 解析之前对其进行修改。
Downloader Middleware 的功能十分强大,修改 User-Agent、处理重定向、设置代理、失败重试、设置 cookies 等功能都需要借助它来实现。下面我们来了解一下 Downloader Middleware 的详细用法。
1. 使用说明
需要说明的是,Scrapy 其实已经提供了许多 Downloader Middleware,比如负责失败重试、自动重定向等功能的 Middleware,它们被 DOWNLOADER_MIDDLEWARES_base 变量所定义。
DOWNLOADER_MIDDLEWARES_base 变量的内容如下所示:
{ 'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100, 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300, 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350, 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400, 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500, 'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550, 'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560, 'scrapy.downloadermiddlewares.redirect.metaRefreshMiddleware': 580, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590, 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600, 'scrapy.downloadermiddlewares.cookies.cookiesMiddleware': 700, 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750, 'scrapy.downloadermiddlewares.stats.DownloaderStats': 850, 'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900, }
这是一个字典格式,字典的键名是 Scrapy 内置的 Downloader Middleware 的名称,键值代表了调用的优先级,优先级是一个数字,数字越小代表越靠近 Scrapy 引擎,数字越大代表越靠近 Downloader。每个 Downloader Middleware 都可以定义 process_request() 和 request_response() 方法来分别处理请求和响应,对于 process_request() 方法来说,优先级数字越小越先被调用,对于 process_response() 方法来说,优先级数字越大越先被调用。
如果自己定义的 Downloader Middleware 要添加到项目里,DOWNLOADER_MIDDLEWARES_base 变量不能直接修改。Scrapy 提供了另外一个设置变量 DOWNLOADER_MIDDLEWARES,我们直接修改这个变量就可以添加自己定义的 Downloader Middleware,以及禁用 DOWNLOADER_MIDDLEWARES_base 里面定义的 Downloader Middleware。下面我们具体来看看 Downloader Middleware 的使用方法。
2. 核心方法
Scrapy 内置的 Downloader Middleware 为 Scrapy 提供了基础的功能,但在项目实战中我们往往需要单独定义 Downloader Middleware。不用担心,这个过程非常简单,我们只需要实现某几个方法即可。
每个 Downloader Middleware 都定义了一个或多个方法的类,核心的方法有如下三个:
·process_request(request, spider)
·process_response(request, response, spider)
·process_exception(request, exception, spider)
我们只需要实现至少一个方法,就可以定义一个 Downloader Middleware。下面我们来看看这三个方法的详细用法。
process_request(request, spider)
Request 被 Scrapy 引擎调度给 Downloader 之前,process_request() 方法就会被调用,也就是在 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 的 errorback() 方法就会回调。如果该异常还没有被处理,那么它便会被忽略。
process_response(request, response, spider)
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 异常抛出,则 Request 的 errorback() 方法会回调。如果该异常还没有被处理,那么它便会被忽略。
process_exception(request, exception, spider)
当 Downloader 或 process_request() 方法抛出异常时,例如抛出 IgnoreRequest 异常,process_exception() 方法就会被调用。方法的返回值必须为 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 Middleware 用法的理解。
3. 项目实战
新建一个项目,命令如下所示:
scrapy startproject scrapydownloadertest
新建了一个 Scrapy 项目,名为 scrapydownloadertest。进入项目,新建一个 Spider,命令如下所示:
scrapy genspider httpbin httpbin.org
新建了一个 Spider,名为 httpbin,源代码如下所示:
import scrapy class HttpbinSpider(scrapy.Spider): name = 'httpbin' allowed_domains = ['httpbin.org'] start_urls = ['http://httpbin.org/'] def parse(self, response): pass ```接下来我们修改 start_urls 为:`['http://httpbin.org/']`。随后将 parse() 方法添加一行日志输出,将 response 变量的 text 属性输出出来,这样我们便可以看到 Scrapy 发送的 Request 信息了。 修改 Spider 内容如下所示: ```python import scrapy class HttpbinSpider(scrapy.Spider): name = 'httpbin' allowed_domains = ['httpbin.org'] start_urls = ['http://httpbin.org/get'] def parse(self, response): self.logger.debug(response.text)
接下来运行此 Spider,执行如下命令:
scrapy crawl httpbin
Scrapy 运行结果包含 Scrapy 发送的 Request 信息,内容如下所示:
{"args": {}, "headers": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,**;q=0.8", "Accept-Encoding": "gzip,deflate,br", "Accept-Language": "en", "Connection": "close", "Host": "httpbin.org", "User-Agent": "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)" }, "origin": "60.207.237.85", "url": "http://httpbin.org/get" }
我们就通过实现 Downloader Middleware 并利用 process_request() 方法成功设置了随机的 User-Agent。
另外,Downloader Middleware 还有 process_response() 方法。Downloader 对 Request 执行下载之后会得到 Response,随后 Scrapy 引擎会将 Response 发送回 Spider 进行处理。但是在 Response 被发送给 Spider 之前,我们同样可以使用 process_response() 方法对 Response 进行处理。比如这里修改一下 Response 的状态码,在 RandomUserAgentMiddleware 添加如下代码:
def process_response(self, request, response, spider): response.status = 201 return response
我们将 response 对象的 status 属性修改为 201,随后将 response 返回,这个被修改后的 Response 就会被发送到 Spider。
我们再在 Spider 里面输出修改后的状态码,在 parse() 方法中添加如下的输出语句:
self.logger.debug('Status Code: ' + str(response.status))
重新运行之后,控制台输出了如下内容:
[httpbin] DEBUG: Status Code: 201
可以发现,Response 的状态码成功修改了。
因此要想对 Response 进行后处理,就可以借助于 process_response() 方法。
另外还有一个 process_exception() 方法,它是用来处理异常的方法。如果需要异常处理的话,我们可以调用此方法。不过这个方法的使用频率相对低一些,在此不用实例演示。
4. 本节代码
本节源代码为:https://github.com/Python3WebSpider/ScrapyDownloaderTest。
5. 结语
本节讲解了 Downloader Middleware 的基本用法。此组件非常重要,是做异常处理和应对反爬处理的核心。后面我们会在实战中应用此组件来处理代理、cookies 等内容。
python学习网,免费的在线学习python平台,欢迎关注!
本文转自:https://cuiqingcai.com/8381.html
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)