asyncio¶
版本 2.0 中的新功能。
Scrapy 部分支持 asyncio
。在您 安装 asyncio 反应器 后,您可以在任何 协程 中使用 asyncio
和 asyncio
支持的库。
安装 asyncio 反应器¶
要启用 asyncio
支持,请将 TWISTED_REACTOR
设置设置为 'twisted.internet.asyncioreactor.AsyncioSelectorReactor'
。
如果您正在使用 CrawlerRunner
,您还需要手动安装 AsyncioSelectorReactor
反应器。您可以使用 install_reactor()
来完成此操作。
install_reactor('twisted.internet.asyncioreactor.AsyncioSelectorReactor')
处理预安装的反应器¶
twisted.internet.reactor
和一些其他 Twisted 导入会将默认的 Twisted 反应器作为副作用安装。一旦安装了 Twisted 反应器,就无法在运行时切换到其他反应器。
如果您 配置了 asyncio Twisted 反应器,并且在运行时 Scrapy 抱怨已安装了其他反应器,则可能是您的代码中有一些此类模块级 Twisted 导入。
您通常可以通过将这些有问题的模块级 Twisted 导入移动到使用它们的方法或函数定义中来解决此问题。例如,如果您有类似以下内容:
from twisted.internet import reactor
def my_function():
reactor.callLater(...)
切换到类似以下内容:
def my_function():
from twisted.internet import reactor
reactor.callLater(...)
或者,您也可以尝试在这些导入发生之前,使用 install_reactor()
手动安装 asyncio 反应器。
等待 Deferreds¶
当未安装 asyncio 反应器时,您可以在协程中直接等待 Deferreds。当它安装后,这将不再可能,因为 Scrapy 协程集成的细节(协程被包装到 asyncio.Future
对象中,而不是直接包装到 Deferred
中),您需要将它们包装到 Futures 中。Scrapy 为此提供了两个帮助程序
- scrapy.utils.defer.deferred_to_future(d: Deferred[_T]) Future[_T] [source]¶
版本 2.6.0 中的新功能。
返回一个
asyncio.Future
对象,该对象包装了 d。当 使用 asyncio 反应器 时,您不能从 定义为协程的 Scrapy 可调用对象 中等待
Deferred
对象,您只能等待Future
对象。将Deferred
对象包装到Future
对象中允许您等待它们。class MySpider(Spider): ... async def parse(self, response): additional_request = scrapy.Request('https://example.org/price') deferred = self.crawler.engine.download(additional_request) additional_response = await deferred_to_future(deferred)
- scrapy.utils.defer.maybe_deferred_to_future(d: Deferred[_T]) Deferred[_T] | Future[_T] [source]¶
版本 2.6.0 中的新功能。
返回 d 作为可以从 定义为协程的 Scrapy 可调用对象 中等待的对象。
您可以在定义为协程的 Scrapy 可调用对象中等待的内容取决于
TWISTED_REACTOR
的值。当不使用 asyncio 反应器时,您只能等待
Deferred
对象。当 使用 asyncio 反应器 时,您只能等待
asyncio.Future
对象。
如果您想编写使用
Deferred
对象但适用于任何反应器的代码,请对所有Deferred
对象使用此函数。class MySpider(Spider): ... async def parse(self, response): additional_request = scrapy.Request('https://example.org/price') deferred = self.crawler.engine.download(additional_request) additional_response = await maybe_deferred_to_future(deferred)
提示
如果您需要在旨在与较低版本的 Scrapy(不提供这些函数,直至 Scrapy 2.0,早期版本不支持 asyncio
)兼容的代码中使用这些函数,您可以将这些函数的实现复制到您自己的代码中。
强制 asyncio 作为需求¶
如果您正在编写一个 组件,该组件需要 asyncio 才能工作,请使用 scrapy.utils.reactor.is_asyncio_reactor_installed()
来 强制它作为需求。例如
from scrapy.utils.reactor import is_asyncio_reactor_installed
class MyComponent:
def __init__(self):
if not is_asyncio_reactor_installed():
raise ValueError(
f"{MyComponent.__qualname__} requires the asyncio Twisted "
f"reactor. Make sure you have it configured in the "
f"TWISTED_REACTOR setting. See the asyncio documentation "
f"of Scrapy for more information."
)
Windows 特定说明¶
Windows 的 asyncio
实现可以使用两种事件循环实现,ProactorEventLoop
(默认)和 SelectorEventLoop
。但是,只有 SelectorEventLoop
可与 Twisted 配合使用。
当您更改 TWISTED_REACTOR
设置或调用 install_reactor()
时,Scrapy 会自动将事件循环类更改为 SelectorEventLoop
。
注意
您使用的其他库可能需要 ProactorEventLoop
,例如,因为它支持子进程(playwright 就是这种情况),因此您不能在 Windows 上将它们与 Scrapy 结合使用(但您应该能够在 WSL 或原生 Linux 上使用它们)。
使用自定义 asyncio 循环¶
您还可以将自定义的 asyncio 事件循环与 asyncio reactor 结合使用。将 ASYNCIO_EVENT_LOOP
设置设置为所需事件循环类的导入路径,以使用它代替默认的 asyncio 事件循环。