下载器中间件(Downloader Middleware)¶
下载器中间件是介于Scrapy的request/response处理的钩子框架。 是用于全局修改Scrapy request和response的一个轻量、底层的系统。
激活下载器中间件¶
要激活下载器中间件组件,将其加入到 DOWNLOADER_MIDDLEWARES 设置中。 该设置是一个字典(dict),键为中间件类的路径,值为其中间件的顺序(order)。
这里是一个例子:
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.CustomDownloaderMiddleware': 543,
}
DOWNLOADER_MIDDLEWARES 设置会与Scrapy定义的 DOWNLOADER_MIDDLEWARES_BASE 设置合并(但不是覆盖), 而后根据顺序(order)进行排序,最后得到启用中间件的有序列表: 第一个中间件是最靠近引擎的,最后一个中间件是最靠近下载器的。
关于如何分配中间件的顺序请查看 DOWNLOADER_MIDDLEWARES_BASE 设置,而后根据您想要放置中间件的位置选择一个值。 由于每个中间件执行不同的动作,您的中间件可能会依赖于之前(或者之后)执行的中间件,因此顺序是很重要的。
如果您想禁止内置的(在 DOWNLOADER_MIDDLEWARES_BASE 中设置并默认启用的)中间件, 您必须在项目的 DOWNLOADER_MIDDLEWARES 设置中定义该中间件,并将其值赋为 None 。 例如,如果您想要关闭user-agent中间件:
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.CustomDownloaderMiddleware': 543,
'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,
}
最后,请注意,有些中间件需要通过特定的设置来启用。更多内容请查看相关中间件文档。
编写您自己的下载器中间件¶
编写下载器中间件十分简单。每个中间件组件是一个定义了以下一个或多个方法的Python类:
- class scrapy.contrib.downloadermiddleware.DownloaderMiddleware¶
- process_request(request, spider)¶
当每个request通过下载中间件时,该方法被调用。
process_request() 必须返回其中之一: 返回 None 、返回一个 Response 对象、返回一个 Request 对象或raise IgnoreRequest 。
如果其返回 None ,Scrapy将继续处理该request,执行其他的中间件的相应方法,直到合适的下载器处理函数(download handler)被调用, 该request被执行(其response被下载)。
如果其返回 Response 对象,Scrapy将不会调用 任何 其他的 process_request() 或 process_exception() 方法,或相应地下载函数; 其将返回该response。 已安装的中间件的 process_response() 方法则会在每个response返回时被调用。
如果其返回 Request 对象,Scrapy则停止调用 process_request方法并重新调度返回的request。当新返回的request被执行后, 相应地中间件链将会根据下载的response被调用。
如果其raise一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用。如果没有任何一个方法处理该异常, 则request的errback(Request.errback)方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)。
参数:
- process_response(request, response, spider)¶
process_request() 必须返回以下之一: 返回一个 Response 对象、 返回一个 Request 对象或raise一个 IgnoreRequest 异常。
如果其返回一个 Response (可以与传入的response相同,也可以是全新的对象), 该response会被在链中的其他中间件的 process_response() 方法处理。
如果其返回一个 Request 对象,则中间件链停止, 返回的request会被重新调度下载。处理类似于 process_request() 返回request所做的那样。
如果其抛出一个 IgnoreRequest 异常,则调用request的errback(Request.errback)。 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)。
参数:
- process_exception(request, exception, spider)¶
当下载处理器(download handler)或 process_request() (下载中间件)抛出异常(包括 IgnoreRequest 异常)时, Scrapy调用 process_exception() 。
process_exception() 应该返回以下之一: 返回 None 、 一个 Response 对象、或者一个 Request 对象。
如果其返回 None ,Scrapy将会继续处理该异常,接着调用已安装的其他中间件的 process_exception() 方法,直到所有中间件都被调用完毕,则调用默认的异常处理。
如果其返回一个 Response 对象,则已安装的中间件链的 process_response() 方法被调用。Scrapy将不会调用任何其他中间件的 process_exception() 方法。
如果其返回一个 Request 对象, 则返回的request将会被重新调用下载。这将停止中间件的 process_exception() 方法执行,就如返回一个response的那样。
参数:
内置下载中间件参考手册¶
本页面介绍了Scrapy自带的所有下载中间件。关于如何使用及编写您自己的中间件,请参考 downloader middleware usage guide.
关于默认启用的中间件列表(及其顺序)请参考 DOWNLOADER_MIDDLEWARES_BASE 设置。
CookiesMiddleware¶
该中间件使得爬取需要cookie(例如使用session)的网站成为了可能。 其追踪了web server发送的cookie,并在之后的request中发送回去, 就如浏览器所做的那样。
以下设置可以用来配置cookie中间件:
单spider多cookie session¶
0.15 新版功能.
Scrapy通过使用 cookiejar Request meta key来支持单spider追踪多cookie session。 默认情况下其使用一个cookie jar(session),不过您可以传递一个标示符来使用多个。
例如:
for i, url in enumerate(urls):
yield Request("http://www.example.com", meta={'cookiejar': i},
callback=self.parse_page)
需要注意的是 cookiejar meta key不是”黏性的(sticky)”。 您需要在之后的request请求中接着传递。例如:
def parse_page(self, response):
# do some processing
return Request("http://www.example.com/otherpage",
meta={'cookiejar': response.meta['cookiejar']},
callback=self.parse_other_page)
COOKIES_DEBUG¶
默认: False
如果启用,Scrapy将记录所有在request(Cookie 请求头)发送的cookies及response接收到的cookies(Set-Cookie 接收头)。
下边是启用 COOKIES_DEBUG 的记录的样例:
2011-04-06 14:35:10-0300 [diningcity] INFO: Spider opened
2011-04-06 14:35:10-0300 [diningcity] DEBUG: Sending cookies to: <GET http://www.diningcity.com/netherlands/index.html>
Cookie: clientlanguage_nl=en_EN
2011-04-06 14:35:14-0300 [diningcity] DEBUG: Received cookies from: <200 http://www.diningcity.com/netherlands/index.html>
Set-Cookie: JSESSIONID=B~FA4DC0C496C8762AE4F1A620EAB34F38; Path=/
Set-Cookie: ip_isocode=US
Set-Cookie: clientlanguage_nl=en_EN; Expires=Thu, 07-Apr-2011 21:21:34 GMT; Path=/
2011-04-06 14:49:50-0300 [diningcity] DEBUG: Crawled (200) <GET http://www.diningcity.com/netherlands/index.html> (referer: None)
[...]
DefaultHeadersMiddleware¶
- class scrapy.contrib.downloadermiddleware.defaultheaders.DefaultHeadersMiddleware¶
该中间件设置 DEFAULT_REQUEST_HEADERS 指定的默认request header。
DownloadTimeoutMiddleware¶
- class scrapy.contrib.downloadermiddleware.downloadtimeout.DownloadTimeoutMiddleware¶
该中间件设置 DOWNLOAD_TIMEOUT 指定的request下载超时时间.
HttpAuthMiddleware¶
- class scrapy.contrib.downloadermiddleware.httpauth.HttpAuthMiddleware¶
该中间件完成某些使用 Basic access authentication (或者叫HTTP认证)的spider生成的请求的认证过程。
在spider中启用HTTP认证,请设置spider的 http_user 及 http_pass 属性。
样例:
from scrapy.contrib.spiders import CrawlSpider class SomeIntranetSiteSpider(CrawlSpider): http_user = 'someuser' http_pass = 'somepass' name = 'intranet.example.com' # .. rest of the spider code omitted ...
HttpCacheMiddleware¶
- class scrapy.contrib.downloadermiddleware.httpcache.HttpCacheMiddleware¶
该中间件为所有HTTP request及response提供了底层(low-level)缓存支持。 其由cache存储后端及cache策略组成。
Scrapy提供了两种HTTP缓存存储后端:
您可以使用 HTTPCACHE_STORAGE 设定来修改HTTP缓存存储后端。 您也可以实现您自己的存储后端。
Scrapy提供了两种了缓存策略:
您可以使用 HTTPCACHE_POLICY 设定来修改HTTP缓存存储后端。 您也可以实现您自己的存储策略。
Dummy策略(默认值)¶
该策略不考虑任何HTTP Cache-Control指令。每个request及其对应的response都被缓存。 当相同的request发生时,其不发送任何数据,直接返回response。
Dummpy策略对于测试spider十分有用。其能使spider运行更快(不需要每次等待下载完成), 同时在没有网络连接时也能测试。其目的是为了能够回放spider的运行过程, 使之与之前的运行过程一模一样 。
使用这个策略请设置:
- HTTPCACHE_POLICY 为 scrapy.contrib.httpcache.DummyPolicy
RFC2616策略¶
该策略提供了符合RFC2616的HTTP缓存,例如符合HTTP Cache-Control, 针对生产环境并且应用在持续性运行环境所设置。该策略能避免下载未修改的数据(来节省带宽,提高爬取速度)。
实现了:
- 当 no-store cache-control指令设置时不存储response/request。
- 当 no-cache cache-control指定设置时不从cache中提取response,即使response为最新。
- 根据 max-age cache-control指令中计算保存时间(freshness lifetime)。
- 根据 Expires 指令来计算保存时间(freshness lifetime)。
- 根据response包头的 Last-Modified 指令来计算保存时间(freshness lifetime)(Firefox使用的启发式算法)。
- 根据response包头的 Age 计算当前年龄(current age)
- 根据 Date 计算当前年龄(current age)
- 根据response包头的 Last-Modified 验证老旧的response。
- 根据response包头的 ETag 验证老旧的response。
- 为接收到的response设置缺失的 Date 字段。
目前仍然缺失:
- Pragma: no-cache 支持 http://www.mnot.net/cache_docs/#PRAGMA
- Vary 字段支持 http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.6
- 当update或delete之后失效相应的response http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.10
- ... 以及其他可能缺失的特性 ..
使用这个策略,设置:
- HTTPCACHE_POLICY 为 scrapy.contrib.httpcache.RFC2616Policy
Filesystem storage backend (默认值)¶
文件系统存储后端可以用于HTTP缓存中间件。
使用该存储端,设置:
- HTTPCACHE_STORAGE 为 scrapy.contrib.httpcache.FilesystemCacheStorage
每个request/response组存储在不同的目录中,包含下列文件:
- request_body - the plain request body
- request_headers - the request headers (原始HTTP格式)
- response_body - the plain response body
- response_headers - the request headers (原始HTTP格式)
- meta - 以Python repr() 格式(grep-friendly格式)存储的该缓存资源的一些元数据。
- pickled_meta - 与 meta 相同的元数据,不过使用pickle来获得更高效的反序列化性能。
目录的名称与request的指纹(参考 scrapy.utils.request.fingerprint)有关,而二级目录是为了避免在同一文件夹下有太多文件 (这在很多文件系统中是十分低效的)。目录的例子:
/path/to/cache/dir/example.com/72/72811f648e718090f041317756c03adb0ada46c7
DBM storage backend¶
0.13 新版功能.
同时也有 DBM 存储后端可以用于HTTP缓存中间件。
默认情况下,其采用 anydbm 模块,不过您也可以通过 HTTPCACHE_DBM_MODULE 设置进行修改。
使用该存储端,设置:
- HTTPCACHE_STORAGE 为 scrapy.contrib.httpcache.DbmCacheStorage
HTTPCache中间件设置¶
HttpCacheMiddleware 可以通过以下设置进行配置:
HTTPCACHE_EXPIRATION_SECS¶
默认: 0
缓存的request的超时时间,单位秒。
超过这个时间的缓存request将会被重新下载。如果为0,则缓存的request将永远不会超时。
在 0.11 版更改: 在0.11版本前,0的意义是缓存的request永远超时。
HTTPCACHE_DIR¶
默认: 'httpcache'
存储(底层的)HTTP缓存的目录。如果为空,则HTTP缓存将会被关闭。 如果为相对目录,则相对于项目数据目录(project data dir)。更多内容请参考 默认的Scrapy项目结构 。
HttpCompressionMiddleware¶
- class scrapy.contrib.downloadermiddleware.httpcompression.HttpCompressionMiddleware¶
该中间件提供了对压缩(gzip, deflate)数据的支持。
ChunkedTransferMiddleware¶
- class scrapy.contrib.downloadermiddleware.chunked.ChunkedTransferMiddleware¶
该中间件添加了对 chunked transfer encoding 的支持。
HttpProxyMiddleware¶
0.8 新版功能.
RedirectMiddleware¶
- class scrapy.contrib.downloadermiddleware.redirect.RedirectMiddleware¶
该中间件根据response的状态处理重定向的request。
通过该中间件的(被重定向的)request的url可以通过 Request.meta 的 redirect_urls 键找到。
RedirectMiddleware 可以通过下列设置进行配置(更多内容请参考设置文档):
如果 Request.meta 包含 dont_redirect 键,则该request将会被此中间件忽略。
MetaRefreshMiddleware¶
- class scrapy.contrib.downloadermiddleware.redirect.MetaRefreshMiddleware¶
该中间件根据meta-refresh html标签处理request重定向。
MetaRefreshMiddleware 可以通过以下设定进行配置 (更多内容请参考设置文档)。
- METAREFRESH_ENABLED
- METAREFRESH_MAXDELAY
该中间件遵循 RedirectMiddleware 描述的 REDIRECT_MAX_TIMES 设定,dont_redirect 及 redirect_urls meta key。
RetryMiddleware¶
- class scrapy.contrib.downloadermiddleware.retry.RetryMiddleware¶
该中间件将重试可能由于临时的问题,例如连接超时或者HTTP 500错误导致失败的页面。
爬取进程会收集失败的页面并在最后,spider爬取完所有正常(不失败)的页面后重新调度。 一旦没有更多需要重试的失败页面,该中间件将会发送一个信号(retry_complete), 其他插件可以监听该信号。
RetryMiddleware 可以通过下列设定进行配置 (更多内容请参考设置文档):
关于HTTP错误的考虑:
如果根据HTTP协议,您可能想要在设定 RETRY_HTTP_CODES 中移除400错误。 该错误被默认包括是由于这个代码经常被用来指示服务器过载(overload)了。而在这种情况下,我们想进行重试。
如果 Request.meta 包含 dont_retry 键, 该request将会被本中间件忽略。
RobotsTxtMiddleware¶
- class scrapy.contrib.downloadermiddleware.robotstxt.RobotsTxtMiddleware¶
该中间件过滤所有robots.txt eclusion standard中禁止的request。
确认该中间件及 ROBOTSTXT_OBEY 设置被启用以确保Scrapy尊重robots.txt。
警告
记住, 如果您在一个网站中使用了多个并发请求, Scrapy仍然可能下载一些被禁止的页面。这是由于这些页面是在robots.txt被下载前被请求的。 这是当前robots.txt中间件已知的限制,并将在未来进行修复。
DownloaderStats¶
- class scrapy.contrib.downloadermiddleware.stats.DownloaderStats¶
保存所有通过的request、response及exception的中间件。
您必须启用 DOWNLOADER_STATS 来启用该中间件。
UserAgentMiddleware¶
- class scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware¶
用于覆盖spider的默认user agent的中间件。
要使得spider能覆盖默认的user agent,其 user_agent 属性必须被设置。
AjaxCrawlMiddleware¶
- class scrapy.contrib.downloadermiddleware.ajaxcrawl.AjaxCrawlMiddleware¶
根据meta-fragment html标签查找 ‘AJAX可爬取’ 页面的中间件。查看 https://developers.google.com/webmasters/ajax-crawling/docs/getting-started 来获得更多内容。
注解
即使没有启用该中间件,Scrapy仍能查找类似于 'http://example.com/!#foo=bar' 这样的’AJAX可爬取’页面。 AjaxCrawlMiddleware是针对不具有 '!#' 的URL,通常发生在’index’或者’main’页面中。