16 KiB
Coroutines
System Message: ERROR/3 (<stdin>, line 7)
Unknown directive type "versionadded".
.. versionadded:: 2.0
Scrapy :ref:`supports <coroutine-support>` the :ref:`coroutine syntax <async>` (i.e. async def).
System Message: ERROR/3 (<stdin>, line 9); backlink
Unknown interpreted text role "ref".System Message: ERROR/3 (<stdin>, line 9); backlink
Unknown interpreted text role "ref".Supported callables
The following callables may be defined as coroutines using async def, and hence use coroutine syntax (e.g. await, async for, async with):
The :meth:`~scrapy.spiders.Spider.start` spider method, which must be defined as an :term:`asynchronous generator`.
System Message: ERROR/3 (<stdin>, line 21); backlink
Unknown interpreted text role "meth".
System Message: ERROR/3 (<stdin>, line 21); backlink
Unknown interpreted text role "term".
:class:`~scrapy.Request` callbacks.
System Message: ERROR/3 (<stdin>, line 26); backlink
Unknown interpreted text role "class".
If you are using any custom or third-party :ref:`spider middleware <topics-spider-middleware>`, see :ref:`sync-async-spider-middleware`.
System Message: ERROR/3 (<stdin>, line 28); backlink
Unknown interpreted text role "ref".
System Message: ERROR/3 (<stdin>, line 28); backlink
Unknown interpreted text role "ref".
System Message: ERROR/3 (<stdin>, line 31)
Unknown directive type "versionchanged".
.. versionchanged:: 2.7 Output of async callbacks is now processed asynchronously instead of collecting all of it first.
The :meth:`process_item` method of :ref:`item pipelines <topics-item-pipeline>`.
System Message: ERROR/3 (<stdin>, line 35); backlink
Unknown interpreted text role "meth".
System Message: ERROR/3 (<stdin>, line 35); backlink
Unknown interpreted text role "ref".
The :meth:`~scrapy.downloadermiddlewares.DownloaderMiddleware.process_request`, :meth:`~scrapy.downloadermiddlewares.DownloaderMiddleware.process_response`, and :meth:`~scrapy.downloadermiddlewares.DownloaderMiddleware.process_exception` methods of :ref:`downloader middlewares <topics-downloader-middleware-custom>`.
System Message: ERROR/3 (<stdin>, line 38); backlink
Unknown interpreted text role "meth".
System Message: ERROR/3 (<stdin>, line 38); backlink
Unknown interpreted text role "meth".
System Message: ERROR/3 (<stdin>, line 38); backlink
Unknown interpreted text role "meth".
System Message: ERROR/3 (<stdin>, line 38); backlink
Unknown interpreted text role "ref".
The :meth:`~scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output` method of :ref:`spider middlewares <topics-spider-middleware>`.
System Message: ERROR/3 (<stdin>, line 46); backlink
Unknown interpreted text role "meth".
System Message: ERROR/3 (<stdin>, line 46); backlink
Unknown interpreted text role "ref".
If defined as a coroutine, it must be an :term:`asynchronous generator`. The input result parameter is an :term:`asynchronous iterable`.
System Message: ERROR/3 (<stdin>, line 50); backlink
Unknown interpreted text role "term".
System Message: ERROR/3 (<stdin>, line 50); backlink
Unknown interpreted text role "term".
See also :ref:`sync-async-spider-middleware` and :ref:`universal-spider-middleware`.
System Message: ERROR/3 (<stdin>, line 53); backlink
Unknown interpreted text role "ref".
System Message: ERROR/3 (<stdin>, line 53); backlink
Unknown interpreted text role "ref".
System Message: ERROR/3 (<stdin>, line 56)
Unknown directive type "versionadded".
.. versionadded:: 2.7
The :meth:`~scrapy.spidermiddlewares.SpiderMiddleware.process_start` method of :ref:`spider middlewares <custom-spider-middleware>`, which must be defined as an :term:`asynchronous generator`.
System Message: ERROR/3 (<stdin>, line 58); backlink
Unknown interpreted text role "meth".
System Message: ERROR/3 (<stdin>, line 58); backlink
Unknown interpreted text role "ref".
System Message: ERROR/3 (<stdin>, line 58); backlink
Unknown interpreted text role "term".
System Message: ERROR/3 (<stdin>, line 62)
Unknown directive type "versionadded".
.. versionadded:: VERSION
:ref:`Signal handlers that support deferreds <signal-deferred>`.
System Message: ERROR/3 (<stdin>, line 64); backlink
Unknown interpreted text role "ref".
Using Deferred-based APIs
In addition to native coroutine APIs Scrapy has some APIs that return a :class:`~twisted.internet.defer.Deferred` object or take a user-supplied function that returns a :class:`~twisted.internet.defer.Deferred` object. These APIs are also asynchronous but don't yet support native async def syntax. In the future we plan to add support for the async def syntax to these APIs or replace them with other APIs where changing the existing ones is possible.
System Message: ERROR/3 (<stdin>, line 72); backlink
Unknown interpreted text role "class".System Message: ERROR/3 (<stdin>, line 72); backlink
Unknown interpreted text role "class".The following Scrapy methods return :class:`~twisted.internet.defer.Deferred` objects (this list is not complete as it only includes methods that we think may be useful for user code):
System Message: ERROR/3 (<stdin>, line 80); backlink
Unknown interpreted text role "class".:class:`scrapy.crawler.Crawler`:
System Message: ERROR/3 (<stdin>, line 84); backlink
Unknown interpreted text role "class".
:meth:`~scrapy.crawler.Crawler.crawl`
System Message: ERROR/3 (<stdin>, line 86); backlink
Unknown interpreted text role "meth".
:meth:`~scrapy.crawler.Crawler.stop`
System Message: ERROR/3 (<stdin>, line 88); backlink
Unknown interpreted text role "meth".
:class:`scrapy.crawler.CrawlerRunner` (also inherited by :class:`scrapy.crawler.CrawlerProcess`):
System Message: ERROR/3 (<stdin>, line 90); backlink
Unknown interpreted text role "class".
System Message: ERROR/3 (<stdin>, line 90); backlink
Unknown interpreted text role "class".
:meth:`~scrapy.crawler.CrawlerRunner.crawl`
System Message: ERROR/3 (<stdin>, line 93); backlink
Unknown interpreted text role "meth".
:meth:`~scrapy.crawler.CrawlerRunner.stop`
System Message: ERROR/3 (<stdin>, line 95); backlink
Unknown interpreted text role "meth".
:meth:`~scrapy.crawler.CrawlerRunner.join`
System Message: ERROR/3 (<stdin>, line 97); backlink
Unknown interpreted text role "meth".
:class:`scrapy.core.engine.ExecutionEngine`:
System Message: ERROR/3 (<stdin>, line 99); backlink
Unknown interpreted text role "class".
:meth:`~scrapy.core.engine.ExecutionEngine.download`
System Message: ERROR/3 (<stdin>, line 101); backlink
Unknown interpreted text role "meth".
:class:`scrapy.signalmanager.SignalManager`:
System Message: ERROR/3 (<stdin>, line 103); backlink
Unknown interpreted text role "class".
:meth:`~scrapy.signalmanager.SignalManager.send_catch_log_deferred`
System Message: ERROR/3 (<stdin>, line 105); backlink
Unknown interpreted text role "meth".
:class:`~scrapy.mail.MailSender`
System Message: ERROR/3 (<stdin>, line 107); backlink
Unknown interpreted text role "class".
:meth:`~scrapy.mail.MailSender.send`
System Message: ERROR/3 (<stdin>, line 109); backlink
Unknown interpreted text role "meth".
The following user-supplied methods can return :class:`~twisted.internet.defer.Deferred` objects (the methods that can also return coroutines are listed in :ref:`coroutine-support`):
System Message: ERROR/3 (<stdin>, line 111); backlink
Unknown interpreted text role "class".System Message: ERROR/3 (<stdin>, line 111); backlink
Unknown interpreted text role "ref".Custom download handlers (see :setting:`DOWNLOAD_HANDLERS`):
System Message: ERROR/3 (<stdin>, line 115); backlink
Unknown interpreted text role "setting".
- download_request()
- close()
Custom downloader implementations (see :setting:`DOWNLOADER`):
System Message: ERROR/3 (<stdin>, line 121); backlink
Unknown interpreted text role "setting".
- fetch()
Custom scheduler implementations (see :setting:`SCHEDULER`):
System Message: ERROR/3 (<stdin>, line 125); backlink
Unknown interpreted text role "setting".
:meth:`~scrapy.core.scheduler.BaseScheduler.open`
System Message: ERROR/3 (<stdin>, line 127); backlink
Unknown interpreted text role "meth".
:meth:`~scrapy.core.scheduler.BaseScheduler.close`
System Message: ERROR/3 (<stdin>, line 129); backlink
Unknown interpreted text role "meth".
Custom dupefilters (see :setting:`DUPEFILTER_CLASS`):
System Message: ERROR/3 (<stdin>, line 131); backlink
Unknown interpreted text role "setting".
- open()
- close()
Custom feed storages (see :setting:`FEED_STORAGES`):
System Message: ERROR/3 (<stdin>, line 137); backlink
Unknown interpreted text role "setting".
- store()
Subclasses of :class:`scrapy.pipelines.media.MediaPipeline`:
System Message: ERROR/3 (<stdin>, line 141); backlink
Unknown interpreted text role "class".
- media_to_download()
- item_completed()
Custom storages used by subclasses of :class:`scrapy.pipelines.files.FilesPipeline`:
System Message: ERROR/3 (<stdin>, line 147); backlink
Unknown interpreted text role "class".
- persist_file()
- stat_file()
In most cases you can use these APIs in code that otherwise uses coroutines, by wrapping a :class:`~twisted.internet.defer.Deferred` object into a :class:`~asyncio.Future` object or vice versa. See :ref:`asyncio-await-dfd` for more information about this.
System Message: ERROR/3 (<stdin>, line 154); backlink
Unknown interpreted text role "class".System Message: ERROR/3 (<stdin>, line 154); backlink
Unknown interpreted text role "class".System Message: ERROR/3 (<stdin>, line 154); backlink
Unknown interpreted text role "ref".For example:
The :meth:`ExecutionEngine.download() <scrapy.core.engine.ExecutionEngine.download>` method returns a :class:`~twisted.internet.defer.Deferred` object that fires with the downloaded response. You can use this object directly in Deferred-based code or convert it into a :class:`~asyncio.Future` object with :func:`~scrapy.utils.defer.maybe_deferred_to_future`.
System Message: ERROR/3 (<stdin>, line 161); backlink
Unknown interpreted text role "meth".
System Message: ERROR/3 (<stdin>, line 161); backlink
Unknown interpreted text role "class".
System Message: ERROR/3 (<stdin>, line 161); backlink
Unknown interpreted text role "class".
System Message: ERROR/3 (<stdin>, line 161); backlink
Unknown interpreted text role "func".
A custom download handler needs to define a download_request() method that returns a :class:`~twisted.internet.defer.Deferred` object. You can write a method that works with Deferreds and returns one directly, or you can write a coroutine and convert it into a function that returns a Deferred with :func:`~scrapy.utils.defer.deferred_f_from_coro_f`.
System Message: ERROR/3 (<stdin>, line 167); backlink
Unknown interpreted text role "class".
System Message: ERROR/3 (<stdin>, line 167); backlink
Unknown interpreted text role "func".
General usage
There are several use cases for coroutines in Scrapy.
Code that would return Deferreds when written for previous Scrapy versions, such as downloader middlewares and signal handlers, can be rewritten to be shorter and cleaner:
System Message: WARNING/2 (<stdin>, line 183)
Cannot analyze code. Pygments package not found.
.. code-block:: python
from itemadapter import ItemAdapter
class DbPipeline:
def _update_item(self, data, item):
adapter = ItemAdapter(item)
adapter["field"] = data
return item
def process_item(self, item, spider):
adapter = ItemAdapter(item)
dfd = db.get_some_data(adapter["id"])
dfd.addCallback(self._update_item, item)
return dfd
becomes:
System Message: WARNING/2 (<stdin>, line 202)
Cannot analyze code. Pygments package not found.
.. code-block:: python
from itemadapter import ItemAdapter
class DbPipeline:
async def process_item(self, item, spider):
adapter = ItemAdapter(item)
adapter["field"] = await db.get_some_data(adapter["id"])
return item
Coroutines may be used to call asynchronous code. This includes other coroutines, functions that return Deferreds and functions that return :term:`awaitable objects <awaitable>` such as :class:`~asyncio.Future`. This means you can use many useful Python libraries providing such code:
System Message: ERROR/3 (<stdin>, line 213); backlink
Unknown interpreted text role "term".System Message: ERROR/3 (<stdin>, line 213); backlink
Unknown interpreted text role "class".System Message: WARNING/2 (<stdin>, line 219)
Cannot analyze code. Pygments package not found.
.. code-block:: python
class MySpiderDeferred(Spider):
# ...
async def parse(self, response):
additional_response = await treq.get("https://additional.url")
additional_data = await treq.content(additional_response)
# ... use response and additional_data to yield items and requests
class MySpiderAsyncio(Spider):
# ...
async def parse(self, response):
async with aiohttp.ClientSession() as session:
async with session.get("https://additional.url") as additional_response:
additional_data = await additional_response.text()
# ... use response and additional_data to yield items and requests
Note
Many libraries that use coroutines, such as aio-libs, require the :mod:`asyncio` loop and to use them you need to :doc:`enable asyncio support in Scrapy<asyncio>`.
System Message: ERROR/3 (<stdin>, line 237); backlink
Unknown interpreted text role "mod".System Message: ERROR/3 (<stdin>, line 237); backlink
Unknown interpreted text role "doc".Note
If you want to await on Deferreds while using the asyncio reactor, you need to :ref:`wrap them<asyncio-await-dfd>`.
System Message: ERROR/3 (<stdin>, line 241); backlink
Unknown interpreted text role "ref".Common use cases for asynchronous code include:
requesting data from websites, databases and other services (in :meth:`~scrapy.spiders.Spider.start`, callbacks, pipelines and middlewares);
System Message: ERROR/3 (<stdin>, line 246); backlink
Unknown interpreted text role "meth".
storing data in databases (in pipelines and middlewares);
delaying the spider initialization until some external event (in the :signal:`spider_opened` handler);
System Message: ERROR/3 (<stdin>, line 250); backlink
Unknown interpreted text role "signal".
calling asynchronous Scrapy methods like :meth:`ExecutionEngine.download` (see :ref:`the screenshot pipeline example<ScreenshotPipeline>`).
System Message: ERROR/3 (<stdin>, line 252); backlink
Unknown interpreted text role "meth".
System Message: ERROR/3 (<stdin>, line 252); backlink
Unknown interpreted text role "ref".
Inline requests
The spider below shows how to send a request and await its response all from within a spider callback:
System Message: WARNING/2 (<stdin>, line 266)
Cannot analyze code. Pygments package not found.
.. code-block:: python
from scrapy import Spider, Request
from scrapy.utils.defer import maybe_deferred_to_future
class SingleRequestSpider(Spider):
name = "single"
start_urls = ["https://example.org/product"]
async def parse(self, response, **kwargs):
additional_request = Request("https://example.org/price")
deferred = self.crawler.engine.download(additional_request)
additional_response = await maybe_deferred_to_future(deferred)
yield {
"h1": response.css("h1").get(),
"price": additional_response.css("#price").get(),
}
You can also send multiple requests in parallel:
System Message: WARNING/2 (<stdin>, line 287)
Cannot analyze code. Pygments package not found.
.. code-block:: python
from scrapy import Spider, Request
from scrapy.utils.defer import maybe_deferred_to_future
from twisted.internet.defer import DeferredList
class MultipleRequestsSpider(Spider):
name = "multiple"
start_urls = ["https://example.com/product"]
async def parse(self, response, **kwargs):
additional_requests = [
Request("https://example.com/price"),
Request("https://example.com/color"),
]
deferreds = []
for r in additional_requests:
deferred = self.crawler.engine.download(r)
deferreds.append(deferred)
responses = await maybe_deferred_to_future(DeferredList(deferreds))
yield {
"h1": response.css("h1::text").get(),
"price": responses[0][1].css(".price::text").get(),
"price2": responses[1][1].css(".color::text").get(),
}
Mixing synchronous and asynchronous spider middlewares
System Message: ERROR/3 (<stdin>, line 320)
Unknown directive type "versionadded".
.. versionadded:: 2.7
The output of a :class:`~scrapy.Request` callback is passed as the result parameter to the :meth:`~scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output` method of the first :ref:`spider middleware <topics-spider-middleware>` from the :ref:`list of active spider middlewares <topics-spider-middleware-setting>`. Then the output of that process_spider_output method is passed to the process_spider_output method of the next spider middleware, and so on for every active spider middleware.
System Message: ERROR/3 (<stdin>, line 322); backlink
Unknown interpreted text role "class".System Message: ERROR/3 (<stdin>, line 322); backlink
Unknown interpreted text role "meth".System Message: ERROR/3 (<stdin>, line 322); backlink
Unknown interpreted text role "ref".System Message: ERROR/3 (<stdin>, line 322); backlink
Unknown interpreted text role "ref".Scrapy supports mixing :ref:`coroutine methods <async>` and synchronous methods in this chain of calls.
System Message: ERROR/3 (<stdin>, line 331); backlink
Unknown interpreted text role "ref".However, if any of the process_spider_output methods is defined as a synchronous method, and the previous Request callback or process_spider_output method is a coroutine, there are some drawbacks to the asynchronous-to-synchronous conversion that Scrapy does so that the synchronous process_spider_output method gets a synchronous iterable as its result parameter:
The whole output of the previous Request callback or process_spider_output method is awaited at this point.
If an exception raises while awaiting the output of the previous Request callback or process_spider_output method, none of that output will be processed.
This contrasts with the regular behavior, where all items yielded before an exception raises are processed.
Asynchronous-to-synchronous conversions are supported for backward compatibility, but they are deprecated and will stop working in a future version of Scrapy.
To avoid asynchronous-to-synchronous conversions, when defining Request callbacks as coroutine methods or when using spider middlewares whose process_spider_output method is an :term:`asynchronous generator`, all active spider middlewares must either have their process_spider_output method defined as an asynchronous generator or :ref:`define a process_spider_output_async method <universal-spider-middleware>`.
System Message: ERROR/3 (<stdin>, line 355); backlink
Unknown interpreted text role "term".System Message: ERROR/3 (<stdin>, line 355); backlink
Unknown interpreted text role "ref".For middleware users
If you have asynchronous callbacks or use asynchronous-only spider middlewares you should make sure the asynchronous-to-synchronous conversions :ref:`described above <sync-async-spider-middleware>` don't happen. To do this, make sure all spider middlewares you use support asynchronous spider output. Even if you don't have asynchronous callbacks and don't use asynchronous-only spider middlewares in your project, it's still a good idea to make sure all middlewares you use support asynchronous spider output, so that it will be easy to start using asynchronous callbacks in the future. Because of this, Scrapy logs a warning when it detects a synchronous-only spider middleware.
System Message: ERROR/3 (<stdin>, line 367); backlink
Unknown interpreted text role "ref".If you want to update middlewares you wrote, see the :ref:`following section <sync-async-spider-middleware-authors>`. If you have 3rd-party middlewares that aren't yet updated by their authors, you can :ref:`subclass <tut-inheritance>` them to make them :ref:`universal <universal-spider-middleware>` and use the subclasses in your projects.
System Message: ERROR/3 (<stdin>, line 377); backlink
Unknown interpreted text role "ref".System Message: ERROR/3 (<stdin>, line 377); backlink
Unknown interpreted text role "ref".System Message: ERROR/3 (<stdin>, line 377); backlink
Unknown interpreted text role "ref".Universal spider middlewares
System Message: ERROR/3 (<stdin>, line 409)
Unknown directive type "versionadded".
.. versionadded:: 2.7
To allow writing a spider middleware that supports asynchronous execution of its process_spider_output method in Scrapy 2.7 and later (avoiding :ref:`asynchronous-to-synchronous conversions <sync-async-spider-middleware>`) while maintaining support for older Scrapy versions, you may define process_spider_output as a synchronous method and define an :term:`asynchronous generator` version of that method with an alternative name: process_spider_output_async.
System Message: ERROR/3 (<stdin>, line 411); backlink
Unknown interpreted text role "ref".System Message: ERROR/3 (<stdin>, line 411); backlink
Unknown interpreted text role "term".For example:
System Message: WARNING/2 (<stdin>, line 421)
Cannot analyze code. Pygments package not found.
.. code-block:: python
class UniversalSpiderMiddleware:
def process_spider_output(self, response, result, spider):
for r in result:
# ... do something with r
yield r
async def process_spider_output_async(self, response, result, spider):
async for r in result:
# ... do something with r
yield r
Note
This is an interim measure to allow, for a time, to write code that works in Scrapy 2.7 and later without requiring asynchronous-to-synchronous conversions, and works in earlier Scrapy versions as well.
In some future version of Scrapy, however, this feature will be deprecated and, eventually, in a later version of Scrapy, this feature will be removed, and all spider middlewares will be expected to define their process_spider_output method as an asynchronous generator.