下载器中间件(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
对象或raiseIgnoreRequest
。如果其返回
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 scrapy.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 scrapy.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
或 spider的download_timeout
属性指定的request下载超时时间.
注解
您也可以使用 download_timeout
Request.meta key 来对每个请求设置下载超时时间. 这种方式在 DownloadTimeoutMiddleware 被关闭时仍然有效.
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 bodyrequest_headers
- the request headers (原始HTTP格式)response_body
- the plain response bodyresponse_headers
- the request headers (原始HTTP格式)meta
- 以Pythonrepr()
格式(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
LevelDB storage backend¶
0.23 新版功能.
A LevelDB storage backend is also available for the HTTP cache middleware.
This backend is not recommended for development because only one process can access LevelDB databases at the same time, so you can’t run a crawl and open the scrapy shell in parallel for the same spider.
In order to use this storage backend:
- set
HTTPCACHE_STORAGE
toscrapy.contrib.httpcache.LeveldbCacheStorage
- install LevelDB python bindings like
pip install leveldb
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
设置为True ,则该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
设为True,
该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’页面中。