Scrapy中间件顺序
Scrapy的文档中提到:
第一个中间件是离引擎最近的,而最后一个中间件是离下载器最近的。
要决定你的中间件的顺序,可以查看DOWNLOADER_MIDDLEWARES_BASE这个设置,并根据你想要插入中间件的位置选择一个值。顺序很重要,因为每个中间件执行的操作不同,你的中间件可能依赖于之前(或之后)某个中间件的执行。
我不太明白的是,值越高的中间件是先执行还是后执行。
例如:
'myproject.middlewares.MW1': 543,
'myproject.middlewares.MW2': 542,
问题:
- 这些中间件中,哪个会先执行?我的尝试显示MW2会先执行。
- 有效的顺序范围是什么?是0到999吗?
2 个回答
我知道这个问题已经有人回答过了,但其实事情比看起来要复杂一些——请求和响应的处理顺序是相反的。
你可以这样理解:
- 0 - 引擎发出请求
- 1..无穷大 - 处理请求的中间件被调用
- 无穷大 - 实际下载发生(如果没有中间件处理请求的话)
- 无穷大..1 - 处理响应的中间件被调用
- 0 - 引擎收到响应
所以……如果我把我的中间件标记为1,它将是第一个被执行的请求中间件,同时也是最后一个被执行的响应中间件……如果我的中间件标记为901,它将是最后一个被执行的请求中间件,同时也是第一个被执行的响应中间件(如果只定义了默认中间件的话)。
其实答案就是,这确实让人困惑。请求的开始离引擎最近(在零的位置),而请求的结束离下载器最近(在高数字的位置)。响应的开始离下载器最近(在高数字的位置),而响应的结束离引擎最近(在零的位置)。这就像是从引擎出发再返回的旅程……下面是来自scrapy的相关代码,让这一切变得有趣(init是从MiddlewareManager复制过来的,仅包含相关的方法):
class DownloaderMiddlewareManager(MiddlewareManager):
def __init__(self, *middlewares):
self.middlewares = middlewares
self.methods = defaultdict(list)
for mw in middlewares:
self._add_middleware(mw)
def _add_middleware(self, mw):
if hasattr(mw, 'process_request'):
self.methods['process_request'].append(mw.process_request)
if hasattr(mw, 'process_response'):
self.methods['process_response'].insert(0, mw.process_response)
if hasattr(mw, 'process_exception'):
self.methods['process_exception'].insert(0, mw.process_exception)
如你所见,请求方法是按顺序添加的(高数字的放在后面),而响应和异常方法则是插入到最前面(高数字的在前面)。
- 这些中哪个会先执行?我试了一下,发现MW2会先执行。
正如你引用的文档所说:
第一个中间件是离引擎最近的,最后一个是离下载器最近的。
所以,值为542的下载器中间件会在值为543的中间件之前执行。这意味着首先会调用myproject.middlewares.MW1.process_request(request, spider)
,然后如果需要修改请求,它会被传递给下一个下载器中间件。
- 这些顺序的有效范围是什么?是0到999吗?
这个值是一个整数。
更新:
看看架构。
还有完整的引用:
DOWNLOADER_MIDDLEWARES设置会与Scrapy中定义的DOWNLOADER_MIDDLEWARES_BASE设置合并(这个设置不应该被覆盖),然后按顺序排序,以得到最终的启用中间件的排序列表:第一个中间件是离引擎最近的,最后一个是离下载器最近的。
所以,由于这些值是整数,它们的范围是Python整数的范围。