根据@Jean-Paul Calderone 的回答,我做了一些调查和测试,以下是我发现的内容。
scrapy内部使用Twisted https://twistedmatrix.com/trac/用于管理请求/响应同步和异步调用的框架。
Scrapy 产生requests(爬行)在async方式,但处理回应(我们的自定义解析回调函数)已完成同步。所以如果你在回调中有阻塞调用,它会阻塞整个引擎.
希望这可以改变。加工时Deferred https://twistedmatrix.com/documents/14.0.1/core/howto/gendefer.html#what-deferreds-don-t-do-make-your-code-asynchronous响应回调结果,Twisted处理案例(twisted.internet.defer.延迟源) https://twistedmatrix.com/trac/browser/trunk/twisted/internet/defer.py#L603 if Deferred对象返回其他Deferred目的。在这种情况下,Twisted 会产生新的异步调用。
基本上,如果我们回来Deferred https://twistedmatrix.com/documents/14.0.1/core/howto/gendefer.html#what-deferreds-don-t-do-make-your-code-asynchronous来自我们的响应回调的对象,这将改变响应回调调用的性质从同步到异步。为此我们可以使用方法推迟到线程 https://twistedmatrix.com/documents/14.0.1/core/howto/gendefer.html#integrating-blocking-code-with-twisted ( 内部调用 https://twistedmatrix.com/trac/browser/trunk/twisted/internet/threads.py#L58 deferToThreadPool(reactor, reactor.getThreadPool()...
- 用于@Jean-Paul Calderone 代码示例)。
工作代码示例是:
from twisted.internet.threads import deferToThread
from twisted.internet import reactor
class SpiderWithBlocking(...):
...
def parse(self, response):
return deferToThread(reactor, self.blocking_call, response.body)
def blocking_call(self, html):
# ....
# do some work in blocking call
return Request(url)
此外,只有回调可以返回 Deferred 对象,但是start_requests
不能(抓取逻辑)。