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导入移动到使用它们的方法或函数定义中来解决问题。例如,如果你有类似以下的内容:
from twisted.internet import reactor
def my_function():
reactor.callLater(...)
切换到类似的内容:
def my_function():
from twisted.internet import reactor
reactor.callLater(...)
或者,您可以在这些导入发生之前,尝试手动安装asyncio反应器,使用install_reactor()。
等待延迟对象¶
当没有安装asyncio反应器时,你可以直接在协程中等待Deferreds。当它被安装后,由于Scrapy协程集成的特殊性(协程被包装成asyncio.Future对象,而不是直接包装成Deferred),这就不再可能了,你需要将它们包装成Futures。Scrapy为此提供了两个辅助工具:
- scrapy.utils.defer.deferred_to_future(d: Deferred[_T]) Future[_T][source]¶
新版本2.6.0中新增。
返回一个包装了d的
asyncio.Future对象。当使用asyncio反应器时,你不能等待 来自
Deferred对象的定义为协程的Scrapy可调用对象,你只能等待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 一起工作。
Scrapy 在您更改 TWISTED_REACTOR 设置或调用 install_reactor() 时,会自动将事件循环类更改为 SelectorEventLoop。
注意
您使用的其他库可能需要
ProactorEventLoop,例如因为它支持
子进程(这是playwright的情况),所以您不能在Windows上与Scrapy一起使用它们(但您应该能够在WSL或原生Linux上使用它们)。
使用自定义的asyncio循环¶
你也可以使用自定义的asyncio事件循环与asyncio反应器。设置ASYNCIO_EVENT_LOOP设置为所需事件循环类的导入路径,以使用它代替默认的asyncio事件循环。