参考资料
Scrapy官方文档:下载器中间件
彻底搞懂Scrapy的中间件(一)
彻底搞懂Scrapy的中间件(二)
彻底搞懂Scrapy的中间件(三)
【反爬虫】下载器中间件讲解
scrapy框架图
图中的数字编号指的是scrapy工作流程中的各个步骤,其中4、5步骤所历经的组件为下载器中间件。
所谓下载器中间件就是连接在Scrapy引擎和下载器之间的组件,主要是处理Scrapy引擎与下载器之间的请求及响应。
下载器中间件在scrapy官方文档中的定义为:下载器中间件是介于Scrapy的request/response处理的钩子框架。 是用于全局修改Scrapy request和response的一个轻量、底层的系统。
通俗点说中间件是Scrapy里面的一个核心概念。使用中间件可以在爬虫的请求发起之前或者请求返回之后对数据进行定制化修改,从而开发出适应不同情况的爬虫。所谓定制化修改主要为更换代理IP,更换Cookies,更换User-Agent,剔除无效返回,自动重试。
假如没有下载器中间件,爬虫流程如图所示:
假如有了下载器中间件,爬虫流程如图所示
Scrapy有以下自带的下载器中间件
{
'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,
}
当然用户也可以自定义自己的下载器中间件,使用自定义的下载器中间件时要在settings.py文件中激活这个中间件
DOWNLOADERMIDDLEWARES = {
'myproject.middlewares.Custom_A_DownloaderMiddleware': 543,
'myproject.middlewares.Custom_B_DownloaderMiddleware': 643,
'myproject.middlewares.Custom_B_DownloaderMiddleware': None,
}
关于中间件顺序,简单画个图说明
其中数字越小越靠近引擎,数字越大越靠近下载器,process_request()优先处理;数字越大的,process_response()优先处理;若需要关闭某个中间件直接设为None即可
假如要自定义下载器中间件,主要编写下面几个方法
class scrapy.downloadermiddlewares.DownloaderMiddleware
process_request(request, spider)
当每个request通过下载中间件时,该方法被调用。
通常它会返回 None
返回一个 Response 对象
返回一个 Request 对象
或raise IgnoreRequest
如果其返回 None ,Scrapy将继续处理该request,执行其他的中间件的相应方法,直到合适的下载器处理函数(download handler)被调用, 该request被执行(其response被下载)。
如果其返回 Response 对象,Scrapy将直接返回该response,而不会再执行其他的中间件。
如果其返回 Request 对象,Scrapy则不再使用之前的request对象去下载数据,而是根据现在返回的request对象去下载数据。
如果其raise一个IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用。 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)
process_response(request, response, spider)
当每个response通过下载中间件时,该方法被调用
通常它会返回 None
返回一个 Response 对象
返回一个 Request 对象
或raise IgnoreRequest 。
如果其返回一个 Response (可以与传入的response相同,也可以是全新的对象), 该response会被在链中的其他中间件的 process_response() 方法处理。
如果其返回一个 Request 对象,则下载器中间件链被切断, 返回的request会被重新调度下载。
如果其抛出一个 IgnoreRequest 异常,则调用request的errback方法(自行设置)。 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)
process_exception(request, exception, spider)
当下载处理器(download handler)或 process_request() 抛出异常(包括 IgnoreRequest 异常)时, Scrapy调用 process_exception()。(对此方法还不太了解)