High-level web crawling and scraping framework. Current version is 2.14.1 (Jan 2026). Requires Python >=3.10. Two major breaking changes in 2.13: start_requests() (sync) replaced by start() (async), and TWISTED_REACTOR now defaults to asyncio — both can silently break existing spiders.
pip install ScrapyVerified import paths — ran on the pinned version, not inferred.
Basic spider. Run with: scrapy crawl quotes -o output.json
Explicitly set TWISTED_REACTOR in settings.py if you need a specific reactor. To restore old behavior: TWISTED_REACTOR = None. New projects use asyncio by default which is correct.
Override start() instead of start_requests() in new spiders. For existing spiders: start_requests() still works but its iteration behavior changed. See 'Delaying start request iteration' in docs to restore previous behavior.
Pin Scrapy<2.13 for Python 3.9 environments.
Use .get() for the first match (returns str or None), .getall() for all matches (returns list of str). Example: response.css('h1::text').get() not response.css('h1::text').Replace return [item1, item2] with yield item1; yield item2. Or return a generator expression. Scrapy 2.13 added a warning for this (WARN_ON_GENERATOR_RETURN_VALUE setting).
Always run scrapy commands from inside a project directory (where scrapy.cfg is). Create a project first: scrapy startproject myproject.
Install Scrapy using `pip install scrapy` (or `pip3 install scrapy`). Ensure the directory where Scrapy's executable is installed (e.g., Python's `Scripts` directory on Windows or `bin` in a virtual environment) is included in your system's PATH. Alternatively, run Scrapy commands using `python -m scrapy`.
Verify Scrapy is installed for your active Python environment using `pip show scrapy`. If not, install it with `pip install scrapy` (or `python3.x -m pip install scrapy` for a specific Python version). Check your project directory and Python path for any conflicting files or folders named `scrapy`.
If your spider uses `async` operations for initial requests, rename `async def start_requests(self)` to `async def start(self)`. The `start()` method should be an `async` generator yielding `Request` objects. If you intend to use synchronous `start_requests()`, ensure it's not defined as `async`.
Explicitly set `TWISTED_REACTOR = 'twisted.internet.asyncioreactor.AsyncioSelectorReactor'` in your `settings.py`. Review your project for any early imports of `twisted.internet.reactor` or other Twisted components and move them to local scopes or after Scrapy's reactor initialization if possible. If running Scrapy from a script, consider using `scrapy.utils.reactor.install_reactor('twisted.internet.asyncioreactor.AsyncioSelectorReactor')` at the very beginning.Ensure that all URLs passed to `scrapy.Request` include a valid scheme, such as `http://` or `https://`. For example, instead of `yield scrapy.Request('example.com')`, use `yield scrapy.Request('https://example.com/')`.