文章目录
- DownloaderMiddleware 下载中间件
-
- process_request 方法
- process_response 方法
- process_exception 方法
DownloaderMiddleware 下载中间件

从上图可以看到DownloaderMiddleware所处的位置在调度器发送请求和返回响应的中途,所以我们可以通过设置下载中间件来更改 Scrapy 的请求和响应。
- 要使用下载中间件,首先我们需要在
settings.py文件
中将其激活,如下

- 要实现
更改 Scrapy 的请求和响应
,我们可以通过以下几个方法来完成!
这里需要注意谨慎返回Request
process_request 方法
def process_request(self, request, spider):
return None
- 通过下载中间件的每个请求都会调用此方法,且必须
return
返回None
,Response对象
,Request 对象
,或 raise IgnoreRequest
中的一个!
返回 |
说明 |
None |
Scrapy 将继续处理 这个请求,执行所有其他中间件,直到最终调用适当的下载器处理程序执行请求(并获取其响应 ) |
Response对象 |
Scrapy 将不再调用 其他process_request()方法 或process_exception()方法 ,也不会启动下载器;而是直接返回那个响应 。但是仍然会经过process_response() 方法 ,如果需要使用selenium等工具来加载JS的话就可以在这里直接返回获取到的响应(body=browser.page_source ) |
Request 对象 |
Scrapy 将终止当前流程,终止调用其他process_request方法 ,将request返回给调度器 ,大多数情况是用于更换新的request请求 |
raise IgnoreRequest |
抛出IgnoreRequest异常 , 该异常就会交个process_exception()方法 进行处理; 如果没有任何一个方法处理该异常,就会调用Request()请求设定的errback参数对应的回调函数处理(参考下列示例) ;如何仍然没有代码处理这个异常,那么该请求就会直接被忽略, 也不会记录在错误日志中 |
Request()请求
中设定的errback对应的回调函数
,官方示例
def parse(self, response):
request = scrapy.Request('http://www.example.com/index.html',
callback=self.parse_page2,
errback=self.errback_page2,
cb_kwargs=dict(main_url=response.url))
yield request
def parse_page2(self, response, main_url):
pass
def errback_page2(self, failure):
yield dict(
main_url=failure.request.cb_kwargs['main_url'],
)
- 这里需要注意:
process_request()方法
在返回Request对象
的情况下,最好是添加一个判断(或者添加dont_filter=False
),否则容易造成死循环!
- 当
返回Request
的时候(请求同一个网址)需要把dont_filter=True
加上,不然scrapy会自动过滤掉已经请求过的网页!
- 这里顺便说一下如何在中间件修改请求地址:我们可以从官方文档中得知
request.url
是一个只读值,不允许修改!如果我们需要修改的话可以使用request.replace()
,如下
import scrapy
import requests
class TestMiddleware:
def process_request(self, request, spider):
print('进入process_request...')
url = 'https://www.baidu.com'
r = requests.get('https://www.baidu.com')
if request.url == 'https://httpbin.org/ip':
request = request.replace(url=url)
return request
return None
process_response 方法
def process_response(self, request, response, spider):
return response
process_response()方法
需要return
返回Response对象
,Request 对象
,或 raise IgnoreRequest
中的一个!
返回 |
说明 |
Response对象 |
返回一个Response对象 ,它可以是原来的response ,也可能是我们修改过的response ;其他流程正常执行! |
Request 对象 |
与process_request方法相同,Scrapy 将终止当前流程,终止调用其他process_request方法 ,将request返回给调度器 |
raise IgnoreRequest |
抛出IgnoreRequest异常 , 该异常就会调用Request()请求设定的errback参数对应的回调函数处理(参考process_request()方法中的示例)`;如何没有代码处理这个异常,那么它会直接被忽略, 也不会记录在错误日志中 |
- 这里需要注意:
process_response()方法
在返回Request对象
的情况下,最好是添加一个判断(或者添加dont_filter=False
),否则容易造成死循环!
- 当
返回Request
的时候(请求同一个网址)需要把dont_filter=True
加上,不然scrapy会自动过滤掉已经请求过的网页!
- 示例代码
def process_response(self, request, response, spider):
print('进入process_response...')
url = 'https://www.baidu.com'
r = requests.get('https://www.baidu.com')
return response
process_exception 方法
def process_exception(self, request, exception, spider):
- 当
下载处理程序
或process_request()(下载器中间件)
引发异常(包括IgnoreRequest异常)时,Scrapy 会调用process_exception()方法。可以return
返回None
,Response对象
或者Request对象
返回 |
说明 |
None |
Scrapy 将调用其他的process_exception()方法继续处理这个异常 |
Response对象 |
Scrapy会将Response对象交给process_response()方法 继续处理,且不再执行其他的process_exception()方法 |
Request 对象 |
Scrapy将终止当前流程,将request返回给调度器 |
- 这里需要注意:
process_response()方法
在返回Request对象
的情况下,最好是添加一个判断(或者添加dont_filter=False
),否则容易造成死循环!
- 当
返回Request
的时候(请求同一个网址)需要把dont_filter=True
加上,不然scrapy会自动过滤掉已经请求过的网页!
- 示例代码
def process_exception(self, request, exception, spider):
print('进入process_exception...')
url = 'https://www.baidu.com'
r = requests.get('https://www.baidu.com')
return scrapy.http.Response(url=url, body=r.content, status=200)