🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Spider 中间件 > 译者:[OSGeo 中国](https://www.osgeo.cn/) Spider中间件是一个Hook框架,可以钩住Scrapy的Spider处理机制,在该机制中,您可以插入自定义功能来处理发送到的响应。 [Spider](spiders.html#topics-spiders) 用于处理和处理由spider生成的请求和项目。 ## 激活 Spider 中间件 要激活 Spider 中间件组件,请将其添加到 [`SPIDER_MIDDLEWARES`](settings.html#std:setting-SPIDER_MIDDLEWARES) 设置,这是一个dict,其键是中间件类路径,其值是中间件命令。 举个例子: ```py SPIDER_MIDDLEWARES = { 'myproject.middlewares.CustomSpiderMiddleware': 543, } ``` 这个 [`SPIDER_MIDDLEWARES`](settings.html#std:setting-SPIDER_MIDDLEWARES) 设置与合并 [`SPIDER_MIDDLEWARES_BASE`](settings.html#std:setting-SPIDER_MIDDLEWARES_BASE) 在scrappy中定义的设置(不打算被重写),然后按顺序排序,以获得已启用中间件的最终排序列表:第一个中间件更接近引擎,最后一个更接近spider。也就是说, [`process_spider_input()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input") 每个中间件的方法将以增加的中间件顺序(100、200、300,…)调用,并且 [`process_spider_output()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output") 每个中间件的方法将按降序调用。 要决定分配给中间件的顺序,请参见 [`SPIDER_MIDDLEWARES_BASE`](settings.html#std:setting-SPIDER_MIDDLEWARES_BASE) 根据要插入中间件的位置设置和选择一个值。顺序很重要,因为每个中间件执行不同的操作,并且您的中间件可能依赖于之前(或之后)应用的一些中间件。 如果要禁用内置中间件(定义于 [`SPIDER_MIDDLEWARES_BASE`](settings.html#std:setting-SPIDER_MIDDLEWARES_BASE) ,默认情况下启用)您必须在项目中定义它。 [`SPIDER_MIDDLEWARES`](settings.html#std:setting-SPIDER_MIDDLEWARES) 设置和分配 `None` 作为其价值。例如,如果要禁用非现场中间件: ```py SPIDER_MIDDLEWARES = { 'myproject.middlewares.CustomSpiderMiddleware': 543, 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None, } ``` 最后,请记住,某些中间商可能需要通过特定设置启用。有关更多信息,请参阅每个中间件文档。 ## 编写自己的 Spider 中间件 每个 Spider 中间件都是一个python类,它定义了下面定义的一个或多个方法。 主要入口点是 `from_crawler` 类方法,它接收 [`Crawler`](api.html#scrapy.crawler.Crawler "scrapy.crawler.Crawler") 实例。这个 [`Crawler`](api.html#scrapy.crawler.Crawler "scrapy.crawler.Crawler") 例如,对象允许您访问 [settings](settings.html#topics-settings) . ```py class scrapy.spidermiddlewares.SpiderMiddleware ``` ```py process_spider_input(response, spider) ``` 对于通过 Spider 中间件进入 Spider 进行处理的每个响应,都会调用此方法。 [`process_spider_input()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input") 应该返回 `None` 或者提出例外。 如果它回来 `None` ,scrapy将继续处理此响应,执行所有其他中间软件,直到最后将响应提交给spider进行处理。 如果它引发了一个异常,那么Scrapy就不会麻烦调用任何其他的 Spider 中间件了。 [`process_spider_input()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input") 并将调用请求errback。errback的输出被链接回另一个方向 [`process_spider_output()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output") 处理,或 [`process_spider_exception()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_exception "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_exception") 如果它引发了一个异常。 | 参数: | * **response** ([`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") object) -- 正在处理的响应 * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 此响应所针对的 Spider | | --- | --- | ```py process_spider_output(response, result, spider) ``` 在处理完响应后,调用此方法,并返回 Spider 返回的结果。 [`process_spider_output()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output") 必须返回 [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") DICT或 [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") 物体。 | 参数: | * **response** ([`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") object) -- 从spider生成此输出的响应 * **result** (an iterable of [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request"), dict or [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") objects) -- Spider 返回的结果 * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 正在处理结果的 Spider | | --- | --- | ```py process_spider_exception(response, exception, spider) ``` 当 Spider 或 [`process_spider_input()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_input") 方法(来自其他 Spider 中间件)引发异常。 [`process_spider_exception()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_exception "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_exception") 应该返回 `None` 或者是 [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") DICT或 [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") 物体。 如果它回来 `None` ,Scrapy将继续处理此异常,执行任何其他 [`process_spider_exception()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_exception "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_exception") 在下面的中间件组件中,直到没有中间件组件离开并且异常到达引擎(在那里记录并丢弃它)。 如果它返回一个不可数 [`process_spider_output()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output") 管道开始,没有其他管道 [`process_spider_exception()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_exception "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_exception") 将被调用。 | 参数: | * **response** ([`Response`](request-response.html#scrapy.http.Response "scrapy.http.Response") object) -- 引发异常时正在处理的响应 * **exception** ([Exception](https://docs.python.org/2/library/exceptions.html#exceptions.Exception) object) -- 引发的异常 * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 引发异常的 Spider | | --- | --- | ```py process_start_requests(start_requests, spider) ``` 0.15 新版功能. 这个方法是用spider的start请求调用的,其工作原理与 [`process_spider_output()`](#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output "scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output") 方法,但它没有关联的响应,必须只返回请求(而不是项)。 它收到一个不可更改的(在 `start_requests` 参数),并且必须返回另一个ITerable of [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request") 物体。 注解 在您的 Spider 中间件中实现此方法时,您应该始终返回一个ITerable(跟随输入的ITerable),而不是全部消费。 `start_requests` 迭代器,因为它可能非常大(甚至没有边界),并导致内存溢出。scrappy引擎设计用于在有能力处理启动请求的情况下提取它们,因此,如果存在停止spider的其他条件(如时间限制或项目/页面计数),则启动请求迭代器实际上可以是无止境的。 | 参数: | * **start_requests** (an iterable of [`Request`](request-response.html#scrapy.http.Request "scrapy.http.Request")) -- 启动请求 * **spider** ([`Spider`](spiders.html#scrapy.spiders.Spider "scrapy.spiders.Spider") object) -- 启动请求所属的 Spider | | --- | --- | ```py from_crawler(cls, crawler) ``` 如果存在,则调用该类方法从 [`Crawler`](api.html#scrapy.crawler.Crawler "scrapy.crawler.Crawler") . 它必须返回中间件的新实例。爬虫对象提供对所有零碎核心组件(如设置和信号)的访问;它是中间件访问它们并将其功能连接到零碎的一种方式。 | 参数: | **crawler** ([`Crawler`](api.html#scrapy.crawler.Crawler "scrapy.crawler.Crawler") object) -- 使用此中间件的爬虫程序 | | --- | --- | ## 内置 Spider 中间件参考 本页描述了Scrapy附带的所有 Spider 中间件组件。有关如何使用它们以及如何编写自己的 Spider 中间件的信息,请参阅 [spider middleware usage guide](#topics-spider-middleware) . 有关默认启用的组件列表(及其顺序),请参见 [`SPIDER_MIDDLEWARES_BASE`](settings.html#std:setting-SPIDER_MIDDLEWARES_BASE) 设置。 ### DepthMiddleware ```py class scrapy.spidermiddlewares.depth.DepthMiddleware ``` DepthmIddleware用于跟踪被擦除站点内每个请求的深度。它通过设置工作 `request.meta['depth'] = 0` 如果之前没有设置值(通常只是第一个请求),则将其递增1。 它可以用来限制要抓取的最大深度,根据深度控制请求优先级,等等。 这个 [`DepthMiddleware`](#scrapy.spidermiddlewares.depth.DepthMiddleware "scrapy.spidermiddlewares.depth.DepthMiddleware") 可以通过以下设置进行配置(有关详细信息,请参阅设置文档): > * [`DEPTH_LIMIT`](settings.html#std:setting-DEPTH_LIMIT) -允许对任何网站进行爬网的最大深度。如果为零,则不施加限制。 > * [`DEPTH_STATS_VERBOSE`](settings.html#std:setting-DEPTH_STATS_VERBOSE) -是否收集每个深度的请求数。 > * [`DEPTH_PRIORITY`](settings.html#std:setting-DEPTH_PRIORITY) -是否根据请求的深度对其进行优先级排序。 ### HttpErrorMiddleware ```py class scrapy.spidermiddlewares.httperror.HttpErrorMiddleware ``` 过滤掉不成功的(错误的)HTTP响应,这样spider就不必处理它们了,而这些(大部分时间)会增加开销,消耗更多的资源,并使spider逻辑更加复杂。 根据 [HTTP standard](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) ,成功的响应是状态代码在200-300范围内的响应。 如果仍要处理超出该范围的响应代码,可以使用 `handle_httpstatus_list` Spider 属性或 [`HTTPERROR_ALLOWED_CODES`](#std:setting-HTTPERROR_ALLOWED_CODES) 设置。 例如,如果您希望您的 Spider 处理404响应,可以这样做: ```py class MySpider(CrawlSpider): handle_httpstatus_list = [404] ``` 这个 `handle_httpstatus_list` 关键 [`Request.meta`](request-response.html#scrapy.http.Request.meta "scrapy.http.Request.meta") 还可以用于指定每个请求允许哪些响应代码。您也可以设置meta键 `handle_httpstatus_all` 到 `True` 如果您想允许请求的任何响应代码。 不过,请记住,处理非200个响应通常是个坏主意,除非你真的知道自己在做什么。 [HTTP Status Code Definitions](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) . #### httpErrorMiddleware设置 ##### HTTPERROR_ALLOWED_CODES 违约: `[]` 通过此列表中包含非200状态代码的所有响应。 ##### HTTPERROR_ALLOW_ALL 违约: `False` 传递所有响应,无论其状态代码如何。 ### OffsiteMiddleware ```py class scrapy.spidermiddlewares.offsite.OffsiteMiddleware ``` 过滤掉对spider所覆盖域之外的URL的请求。 这个中间件过滤掉主机名不在spider中的每个请求 [`allowed_domains`](spiders.html#scrapy.spiders.Spider.allowed_domains "scrapy.spiders.Spider.allowed_domains") 属性。也允许列表中任何域的所有子域。例如规则 `www.example.org` 也将允许 `bob.www.example.org` 但不是 `www2.example.com` 也不 `example.com` . 当您的spider返回一个不属于spider覆盖的域的请求时,这个中间件将记录一个与这个类似的调试消息: ```py DEBUG: Filtered offsite request to 'www.othersite.com': <GET http://www.othersite.com/some/page.html> ``` 为了避免在日志中填充过多的噪声,它将只为每个过滤后的新域打印其中一条消息。例如,如果另一个请求 `www.othersite.com` 已筛选,将不打印日志消息。但如果有人要求 `someothersite.com` 过滤后,将打印一条消息(但仅针对过滤后的第一个请求)。 如果 Spider 没有定义 [`allowed_domains`](spiders.html#scrapy.spiders.Spider.allowed_domains "scrapy.spiders.Spider.allowed_domains") 属性,或者属性为空,异地中间件将允许所有请求。 如果请求具有 `dont_filter` 属性集,非现场中间件将允许请求,即使其域未在允许的域中列出。 ### RefererMiddleware ```py class scrapy.spidermiddlewares.referer.RefererMiddleware ``` 填充请求 `Referer` 头,基于生成它的响应的URL。 #### ReferermIddleware设置 ##### REFERER_ENABLED 0.15 新版功能. 违约: `True` 是否启用引用中间件。 ##### REFERRER_POLICY 1.4 新版功能. 违约: `'scrapy.spidermiddlewares.referer.DefaultReferrerPolicy'` [Referrer Policy](https://www.w3.org/TR/referrer-policy) 填充请求“引用”头时应用。 注解 您还可以使用特殊的 `"referrer_policy"` [Request.meta](request-response.html#topics-request-meta) 键,其可接受值与 `REFERRER_POLICY` 设置。 ###### 推荐人政策的可接受值 * 或者是到 `scrapy.spidermiddlewares.referer.ReferrerPolicy` 子类-自定义策略或内置策略之一(参见下面的类)。 * 或标准W3C定义的字符串值之一, * 或特殊 `"scrapy-default"` . | 字符串值 | 类名(作为字符串) | | --- | --- | | `"scrapy-default"` (默认) | [`scrapy.spidermiddlewares.referer.DefaultReferrerPolicy`](#scrapy.spidermiddlewares.referer.DefaultReferrerPolicy "scrapy.spidermiddlewares.referer.DefaultReferrerPolicy") | | ["no-referrer"](https://www.w3.org/TR/referrer-policy/#referrer-policy-no-referrer) | [`scrapy.spidermiddlewares.referer.NoReferrerPolicy`](#scrapy.spidermiddlewares.referer.NoReferrerPolicy "scrapy.spidermiddlewares.referer.NoReferrerPolicy") | | ["no-referrer-when-downgrade"](https://www.w3.org/TR/referrer-policy/#referrer-policy-no-referrer-when-downgrade) | [`scrapy.spidermiddlewares.referer.NoReferrerWhenDowngradePolicy`](#scrapy.spidermiddlewares.referer.NoReferrerWhenDowngradePolicy "scrapy.spidermiddlewares.referer.NoReferrerWhenDowngradePolicy") | | ["same-origin"](https://www.w3.org/TR/referrer-policy/#referrer-policy-same-origin) | [`scrapy.spidermiddlewares.referer.SameOriginPolicy`](#scrapy.spidermiddlewares.referer.SameOriginPolicy "scrapy.spidermiddlewares.referer.SameOriginPolicy") | | ["origin"](https://www.w3.org/TR/referrer-policy/#referrer-policy-origin) | [`scrapy.spidermiddlewares.referer.OriginPolicy`](#scrapy.spidermiddlewares.referer.OriginPolicy "scrapy.spidermiddlewares.referer.OriginPolicy") | | ["strict-origin"](https://www.w3.org/TR/referrer-policy/#referrer-policy-strict-origin) | [`scrapy.spidermiddlewares.referer.StrictOriginPolicy`](#scrapy.spidermiddlewares.referer.StrictOriginPolicy "scrapy.spidermiddlewares.referer.StrictOriginPolicy") | | ["origin-when-cross-origin"](https://www.w3.org/TR/referrer-policy/#referrer-policy-origin-when-cross-origin) | [`scrapy.spidermiddlewares.referer.OriginWhenCrossOriginPolicy`](#scrapy.spidermiddlewares.referer.OriginWhenCrossOriginPolicy "scrapy.spidermiddlewares.referer.OriginWhenCrossOriginPolicy") | | ["strict-origin-when-cross-origin"](https://www.w3.org/TR/referrer-policy/#referrer-policy-strict-origin-when-cross-origin) | [`scrapy.spidermiddlewares.referer.StrictOriginWhenCrossOriginPolicy`](#scrapy.spidermiddlewares.referer.StrictOriginWhenCrossOriginPolicy "scrapy.spidermiddlewares.referer.StrictOriginWhenCrossOriginPolicy") | | ["unsafe-url"](https://www.w3.org/TR/referrer-policy/#referrer-policy-unsafe-url) | [`scrapy.spidermiddlewares.referer.UnsafeUrlPolicy`](#scrapy.spidermiddlewares.referer.UnsafeUrlPolicy "scrapy.spidermiddlewares.referer.UnsafeUrlPolicy") | ```py class scrapy.spidermiddlewares.referer.DefaultReferrerPolicy ``` “降级时无引用”的变体,加上如果父请求正在使用,则不发送“引用”。 `file://` 或 `s3://` 方案。 警告 Scrapy的默认引用策略-就像 ["no-referrer-when-downgrade"](https://www.w3.org/TR/referrer-policy/#referrer-policy-no-referrer-when-downgrade) ,W3C推荐的浏览器值-将从任何 `http(s)://` 对任何 `https://` URL,即使域不同。 ["same-origin"](https://www.w3.org/TR/referrer-policy/#referrer-policy-same-origin) 如果要删除跨域请求的引用者信息,可能是更好的选择。 ```py class scrapy.spidermiddlewares.referer.NoReferrerPolicy ``` [https://www.w3.org/tr/referer-policy/referer-policy-no-referer](https://www.w3.org/tr/referer-policy/referer-policy-no-referer) 最简单的策略是“无引用”,它指定不将引用信息与从特定请求客户机发出的请求一起发送到任何源站。标题将完全省略。 ```py class scrapy.spidermiddlewares.referer.NoReferrerWhenDowngradePolicy ``` [https://www.w3.org/tr/referer-policy](https://www.w3.org/tr/referer-policy)/降级时没有referer-policy “降级时不引用”策略将完整的URL以及来自受TLS保护的环境设置对象的请求发送到可能值得信任的URL,以及来自不受TLS保护的客户端的请求发送到任何源站。 另一方面,来自受TLS保护的客户端对不可能可信的URL的请求将不包含引用者信息。将不发送引用HTTP头。 如果没有另外指定策略,这是用户代理的默认行为。 注解 “降级时不引用”策略是W3C推荐的默认策略,主要Web浏览器使用该策略。 但是,它不是Scrapy的默认引用者策略(请参见 [`DefaultReferrerPolicy`](#scrapy.spidermiddlewares.referer.DefaultReferrerPolicy "scrapy.spidermiddlewares.referer.DefaultReferrerPolicy") ) ```py class scrapy.spidermiddlewares.referer.SameOriginPolicy ``` [https://www.w3.org/tr/referer-policy/referer-policy-same-origin](https://www.w3.org/tr/referer-policy/referer-policy-same-origin) “同一来源”策略指定,当从特定请求客户端发出同一来源请求时,删除作为引用的完整URL作为引用信息发送。 另一方面,跨源请求将不包含引用者信息。将不发送引用HTTP头。 ```py class scrapy.spidermiddlewares.referer.OriginPolicy ``` [https://www.w3.org/tr/referer-policy/referer-policy-origin](https://www.w3.org/tr/referer-policy/referer-policy-origin) “来源”策略指定,在从特定请求客户机发出相同的来源请求和跨来源请求时,仅将请求客户机来源的ASCII序列化作为引用信息发送。 ```py class scrapy.spidermiddlewares.referer.StrictOriginPolicy ``` [https://www.w3.org/tr/referer-policy/referer-policy-strict-origin](https://www.w3.org/tr/referer-policy/referer-policy-strict-origin) “strict来源”策略在发出请求时发送请求客户端来源的ASCII序列化:从受TLS保护的环境设置对象发送到可能值得信任的URL,从不受TLS保护的环境设置对象发送到任何来源。 另一方面,来自受TLS保护的请求客户端对不可能可信的URL的请求将不包含引用者信息。将不发送引用HTTP头。 ```py class scrapy.spidermiddlewares.referer.OriginWhenCrossOriginPolicy ``` [https://www.w3.org/tr/referer-policy](https://www.w3.org/tr/referer-policy)/跨来源引用策略来源 “跨源站时的源站”策略指定,当从特定请求客户机发出相同的源站请求时,剥离用作引用的完整URL作为引用信息发送,而在从特定请求客户机发出跨源站请求时,仅将请求客户机源站的ASCII序列化作为引用信息发送。请求客户端。 ```py class scrapy.spidermiddlewares.referer.StrictOriginWhenCrossOriginPolicy ``` [https://www.w3.org/tr/referer-policy](https://www.w3.org/tr/referer-policy)/跨来源时引用策略strict来源 “跨来源时strict来源”策略指定,当从特定请求客户端发出同一来源请求时,剥离用作引用的完整URL作为引用信息发送,并且在发出跨来源请求时,仅将请求客户端来源的ASCII序列化作为引用信息发送: * 从受TLS保护的环境设置对象到可能值得信赖的URL,以及 * 从非TLS保护的环境设置对象到任何源站。 另一方面,来自受TLS保护的客户端对不可能可信的URL的请求将不包含引用者信息。将不发送引用HTTP头。 ```py class scrapy.spidermiddlewares.referer.UnsafeUrlPolicy ``` [https://www.w3.org/tr/referer-policy/referer-policy-unsafe-url](https://www.w3.org/tr/referer-policy/referer-policy-unsafe-url) “不安全的URL”策略指定一个完整的URL,被剥离用作引用,与来自特定请求客户端的跨源请求和同一源请求一起发送。 注意:保险单的名称不是谎言,它是不安全的。此策略将泄漏从受TLS保护的资源到不安全源的源和路径。仔细考虑为可能敏感的文档设置此类策略的影响。 警告 不建议使用“不安全URL”策略。 ### UrlLengthMiddleware ```py class scrapy.spidermiddlewares.urllength.UrlLengthMiddleware ``` 筛选出URL超过URL长度限制的请求 这个 [`UrlLengthMiddleware`](#scrapy.spidermiddlewares.urllength.UrlLengthMiddleware "scrapy.spidermiddlewares.urllength.UrlLengthMiddleware") 可以通过以下设置进行配置(有关详细信息,请参阅设置文档): > * [`URLLENGTH_LIMIT`](settings.html#std:setting-URLLENGTH_LIMIT) -允许已爬网URL的最大URL长度。