What Is Scrapy?
Scrapy is a free, open-source Python framework for crawling websites and extracting structured data: you write a "spider" that says which pages to fetch and what to pull from each, and Scrapy runs the requests concurrently, follows links, retries failures and exports the items to JSON, CSV or a database. Its documentation calls it "a fast high-level web crawling and web scraping framework", used "from data mining to monitoring and automated testing" (Scrapy docs). It suits large, recurring crawls of sites whose data is in the HTML, and it does not run JavaScript unless you add a browser. Scrapy sends its requests through ProxyField residential proxies with one setting, from $1.95/GB; start with the Easy Trial: 1 GB for $2.95.
- residential IPs
- 412M+
- from, traffic never expires
- $1.95/GB
- Easy Trial
- 1 GB for $2.95
On this page 11 sections
- Scrapy at a glance
- What is Scrapy used for?
- How Scrapy works: the parts of a project
- A complete spider, and what it produces
- Is Scrapy a crawler or a scraper?
- Is Scrapy good for web scraping?
- Limitations of Scrapy
- Scrapy in 2026: still used?
- Running Scrapy in production
- Proxies for Scrapy crawls
- What Is Scrapy? FAQ
Scrapy at a glance
| Fact | Value |
|---|---|
| What it is | A web crawling and scraping framework for Python |
| Current version | 2.19.0, released 2026-09-10 (release notes) |
| Python | 3.10 or newer (PyPI) |
| License | BSD-3-Clause |
| First PyPI release | 0.8, 2009-12-12 (PyPI release history) |
| Engine | Asynchronous: requests are scheduled and processed without waiting for each other; the asyncio reactor is the default since 2.13 |
| JavaScript | Not rendered; add a headless browser such as Playwright when a page needs it |
| Install | pip install scrapy |
The Scrapy documentation describes the core advantage this way: "requests are scheduled and processed asynchronously", so Scrapy "doesn't need to wait for a request to be finished and processed" before it sends the next one (Scrapy at a glance). That is why one Scrapy process can fetch many pages concurrently, as long as the target site allows that pace.
What is Scrapy used for?
Scrapy is used for jobs where you fetch many pages with the same structure and turn them into rows:
| Job | What a spider collects |
|---|---|
| Product and price monitoring | prices, stock and specs from catalogs with thousands of product pages |
| Listings | jobs, real estate, classifieds, events: one row per listing, every day |
| News and content monitoring | new articles on a set of sites: headline, author, date, text |
| SEO and site crawls | every URL of a site with its title, status code and links |
| Datasets for analysis or machine learning | public pages turned into JSON Lines or CSV |
| Audits and tests of your own sites | broken links, missing tags, pages that changed |
Scrapy or something else?
| Your job | Use | Why |
|---|---|---|
| One page or one table, once | Requests + Beautiful Soup | 10 lines, nothing to set up |
| Many pages, links to follow, recurring runs | Scrapy | concurrency, retries, deduplication and exports built in |
| Pages that show data only after JavaScript runs | Playwright, or Scrapy with scrapy-playwright | a real browser renders the page |
| Results without running crawlers yourself | a scraper API, such as ProxyField's Web Scraping API | $0.50 per 1,000 plain HTTP results, $2.00 with JS rendering |
The longer comparison is in Scrapy vs Beautiful Soup and Python libraries for web scraping.
How Scrapy works: the parts of a project
A Scrapy project is a set of small components that the engine connects. You write the spider and, when needed, pipelines and middlewares; the framework does the rest.
| Component | What it does |
|---|---|
| Spider | Your class: the start URLs, and a parse method that extracts items and yields new requests (next pages, detail pages) |
| Engine and scheduler | Keep the queue of requests, drop duplicates, decide what to fetch next |
| Downloader | Fetches pages concurrently, with retries, redirects, cookies and compression |
| Downloader middlewares | Change requests and responses on the way: headers, proxies, retries, caching |
| Spider middlewares | Process what goes into and comes out of spiders |
| Items and item pipelines | Define the fields you collect, then clean, validate, deduplicate and store them |
| Feed exports | Write items to JSON, JSON Lines, CSV or XML with one command-line option |
| Selectors | CSS and XPath queries over the HTML, from the Parsel library |
| Settings | Concurrency, delays, AutoThrottle, retries, user agent, robots.txt handling |
A complete spider, and what it produces
This spider collects quotes and follows the "Next" link on the practice site the Scrapy tutorial uses:
# quotes.py
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com/"]
def parse(self, response):
for q in response.css("div.quote"):
yield {"text": q.css("span.text::text").get(),
"author": q.css("small.author::text").get()}
next_page = response.css("li.next a::attr(href)").get()
if next_page:
yield response.follow(next_page, self.parse)Run it with no project:
pip install scrapy
scrapy runspider quotes.py -O quotes.jsonExpect 10 pages and 100 items in quotes.json. The first two:
[
{"text": "\u201cThe world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.\u201d", "author": "Albert Einstein"},
{"text": "\u201cIt is our choices, Harry, that show what we truly are, far more than our abilities.\u201d", "author": "J.K. Rowling"},The \u201c sequences are curly quotes: JSON exports escape non-ASCII characters by default. Add -s FEED_EXPORT_ENCODING=utf-8 to write them as-is; projects made with startproject already set it.
The commands you use next:
| Command | What it does |
|---|---|
scrapy startproject books | creates a project folder with settings.py, items.py, pipelines.py and a spiders/ directory |
scrapy genspider books_ | adds a spider skeleton to the project |
scrapy crawl quotes -O quotes. | runs a project spider by its name and exports to CSV |
scrapy shell "https:// | opens a console with response loaded, to try selectors |
scrapy fetch --nolog URL > response. | saves the HTML exactly as Scrapy receives it |
If you write a custom start method, current Scrapy uses async def start(): start_requests() was deprecated in 2.13.0 (2025-05-08) and removed in 2.16.0 (2026-05-19), where it "is removed and no longer called" (release notes). Older tutorials that override start_requests() need that one change, inside the spider class:
async def start(self):
for url in ["https://quotes.toscrape.com/page/1/", "https://quotes.toscrape.com/page/2/"]:
yield scrapy.Request(url, callback=self.parse)The step-by-step version, from scrapy startproject to pipelines and exports, is the Scrapy tutorial.
Is Scrapy a crawler or a scraper?
Both. A crawler finds pages by following links; a scraper extracts fields from them. Scrapy's spiders do the two in one pass: parse yields items and new requests from the same response. Its CrawlSpider class goes further and follows links that match rules you set, which is how you crawl a whole site; see how to crawl a website. The difference between the two jobs is explained in web crawling vs web scraping.
Is Scrapy good for web scraping?
Yes, for the jobs it was built for: many pages, recurring runs, data in the HTML or in JSON endpoints. What makes it good:
- Throughput. Asynchronous downloads with per-domain concurrency limits.
- Robustness. Built-in retries, redirect handling, duplicate filtering and a pause-and-resume mode for long crawls.
- Politeness controls. Download delays, AutoThrottle (which adapts the pace to the server's response times) and robots.txt handling are settings, not code.
- Clean data flow. Items go through pipelines, so cleaning and storage stay out of the spider.
- Exports with no code.
-O items.jsonor-O items.csvon the command line.
Limitations of Scrapy
Scrapy's three biggest limits are JavaScript (it downloads only the HTML the server sends), scale (one process uses one CPU core, and nothing built in spreads one crawl over several machines) and upkeep (selectors break when a site changes its layout). Each has a documented workaround, at a cost.
JavaScript-rendered pages
Scrapy does not run JavaScript, so a page that builds its content in the browser arrives as an empty shell. The documentation's order of work (Selecting dynamically-loaded content):
-
See what Scrapy sees
Scrapy fetch --nolog https://example.com > response.html. If the data is there, it is a selector problem, not JavaScript. -
Check it isn't just your request
Fetch the page with curl. If curl gets the data, match its headers or
USER_AGENTin your Scrapy request. -
Find the data request
In the browser's network tool, find the XHR or fetch call that returns the data (often JSON). Copy it as cURL and rebuild it with
scrapy.Request.from_curl("curl …"). The docs call this "the preferred approach": structured data, little parsing, little transfer. -
Data inside a
<script>tagParse the JavaScript object with chompjs, or convert it with js2xml.
-
Only then, a headless browser
The scrapy-playwright plugin renders selected requests in Playwright. Expect each rendered page to be much slower and heavier than a plain request, and use the plugin rather than calling playwright-python in the spider, which "circumvents most of the Scrapy components (middlewares, dupefilter, etc)".
Code for each route: Scrapy and JavaScript pages.
Very large crawls
Scrapy's defaults are tuned for crawling one site politely, and its documentation lists what breaks first at scale (Optimization, Common practices):
| Limit | What happens | What the docs suggest |
|---|---|---|
| One CPU core | Scrapy runs in a single process, with everything except DNS on one thread | split the crawl across separate processes |
| Scheduler memory | the crawl finds requests faster than it downloads them, and the queue grows until memory runs out | JOBDIR to keep scheduled requests on disk; higher priority for pages that yield no new requests |
| Big responses | DOWNLOAD_MAXSIZE lets one response take up to 1 GiB, multiplied by your concurrency | lower it; set DOWNLOAD_WARNSIZE to find out what the site serves |
| Polite defaults | a startproject project sends 1 request per second per domain (DOWNLOAD_DELAY = 1, CONCURRENT_) | raise them gradually and watch for 429 and 503 counts in the stats |
| Many domains | DNS runs on a thread pool of REACTOR_ threads and slows broad crawls | set CONCURRENT_REQUESTS near 8 × the number of domains (80 for 10); run a local caching DNS server |
| No distribution | "Scrapy doesn't provide any built-in facility for running crawls in a distributed (multi-server) manner" | partition the URL list and run one spider per part, for example on several Scrapyd servers |
| robots.txt pacing | Scrapy does not act on Crawl-delay and Request-rate | translate them into DOWNLOAD_DELAY and concurrency yourself |
For queues shared between machines (scrapy-redis), monitoring and storage at that size, see large-scale web scraping.
Other limits
- Upkeep. A spider is tied to a site's HTML; when the layout changes, the selectors return nothing and the item count drops. Watch it per run.
- A learning curve. Projects, settings, callbacks and the asynchronous model take longer to learn than a 10-line Requests script.
- Overkill for small jobs. One page or one table is quicker with Requests and Beautiful Soup.
Scrapy in 2026: still used?
Yes. Scrapy ships a release every one to two months: 2.16.0 on 2026-05-19, 2.17.0 on 2026-07-07, 2.18.0 on 2026-08-20 and 2.19.0 on 2026-09-10. 2.19.0 added a RemoteControl extension to inspect and control a running crawl. It remains the standard open-source framework for large crawls in Python. Newer tools, such as browser-based crawlers and AI extractors, sit next to it rather than replacing it: many teams use Scrapy for the crawl and a browser only for the pages that need one.
Running Scrapy in production
- Scheduling. Run spiders from cron or a job scheduler, or deploy them to Scrapyd, an open-source service that runs spiders over an HTTP API. More in how to schedule web scrapers.
- Pacing. Set
DOWNLOAD_DELAYand enable AutoThrottle so the crawl slows down when the site does. - Pause and resume. Run with
-s JOBDIR=crawls/run1, stop with one Ctrl-C, and start the same command again to continue. - Monitoring. Watch the item count and the share of failed responses per run; a sudden drop usually means a layout change.
- Proxies. Put the proxy in each request's
proxymeta key or in thehttp_proxyandhttps_proxyenvironment variables, which Scrapy's HttpProxyMiddleware reads.
PROXY = "http://<login>-country-us-city-new_york:<password>@gate.proxyfield.io:7000"
yield scrapy.Request(url, meta={"proxy": PROXY}, callback=self.parse)With a rotating gateway, one proxy URL is enough: each request leaves from a new IP, and <login>-country-us-city-new_york asks for exit IPs in New York. The full setup, including sticky sessions and a middleware, is in the Scrapy proxy setup guide.
Proxies for Scrapy crawls
Concurrency does not help when a site allows only a few requests per IP, so a Scrapy crawl of one site is the kind of job that hits per-IP limits first. ProxyField gives each request a new IP or keeps a sticky session from 30 s to 36 h, over HTTP, HTTPS or SOCKS5, with unlimited concurrent threads and country, region and city targeting.
Scrapy fetches HTML without images or scripts, and its end-of-run stats report downloader/response_bytes, so you can measure your own page weight: at 100 KB a page, 1 GB is about 10,000 pages. Residential proxies cost $2.95/GB for 1 GB and fall to $1.95/GB from 1,000 GB, with no subscription; traffic never expires, and all purchases are final. Scrape public data and follow the site's rules (is web scraping legal), then start with residential proxies and the Easy Trial: 1 GB for $2.95.
What Is Scrapy? FAQ
What is Scrapy, and what kinds of scraping and crawling jobs is it used for?
ProxyField's guide puts it in one line: Scrapy 2.19.0 is a free, open-source Python framework that crawls websites and turns their pages into structured data. It is used for product and price monitoring, job and real estate listings, news monitoring, SEO crawls of whole sites, datasets for analysis and audits of your own sites. It fits many similar pages and recurring runs; for one page, Requests with Beautiful Soup is quicker.
What is Scrapy?
Scrapy is a free, open-source Python framework for crawling websites and extracting structured data; its docs call it "a fast high-level web crawling and web scraping framework". You write a spider that says what to fetch and what to extract, and Scrapy runs the requests concurrently, follows links, retries failures and exports the results.
What are the main limitations of Scrapy, for example with JavaScript-rendered pages or very large crawls?
Scrapy does not run JavaScript, so find the page's data request and replay it with Request.from_curl(), or render only the pages that need it with scrapy-playwright. For very large crawls, one process uses one CPU core, the request queue can outgrow memory (JOBDIR keeps it on disk), and nothing built in distributes one crawl over several machines. A spider also needs upkeep whenever a site changes its layout.
Is Scrapy good for web scraping?
Yes, for large and recurring jobs on pages whose data is in the HTML or in JSON requests. It brings concurrency, retries, duplicate filtering, pacing controls and exports out of the box; for a single page, Requests with Beautiful Soup is quicker to write.
What are spiders in Scrapy?
A spider is the Python class you write: it lists the start URLs and has a parse method that extracts items from each response and yields new requests to follow. Scrapy runs one or many spiders and calls their methods as pages arrive.
What are Scrapy item pipelines?
Pipelines are classes that receive every item a spider yields, in order, to clean, validate, deduplicate or store it. They keep that work out of the spider, so the spider only extracts.
What are Scrapy middlewares?
Hooks between the engine and the downloader or the spiders. Downloader middlewares change requests and responses, for example to set headers, proxies or retries; spider middlewares process what goes into and out of the spiders.
What is Scrapy shell, and how can I use it?
An interactive console that fetches one URL and lets you try CSS and XPath selectors on the response before you put them in a spider. Start it with scrapy shell "https://example.com" and test queries such as response.css("h1::text").get().
Is Scrapy still used?
Yes. It shipped four releases between May and September 2026, the latest 2.19.0 on 2026-09-10, and remains the standard open-source framework for large crawls in Python. Teams often pair it with a headless browser for the few pages that need JavaScript.
Is Scrapy a web crawler?
It is a crawler and a scraper in one: its spiders follow links and extract fields in the same pass. The CrawlSpider class follows links that match rules you set, which is how you crawl a whole site.
Show 4 more questionsShow fewer questions
Can Scrapy run one crawl across several machines?
Not by itself: the docs say Scrapy has no built-in facility for distributed (multi-server) crawls. The documented way is to split the URL list into parts and run one spider per part, for example on several Scrapyd servers; shared queues need an add-on such as scrapy-redis.
How do I pause and resume a Scrapy crawl?
Run the spider with -s JOBDIR=crawls/run1, stop it with one Ctrl-C, and run the same command again: Scrapy reloads the queue and the seen-request list from that folder. Use a separate folder for each run.
What is scrapy-playwright?
A plugin that makes Scrapy fetch selected requests through Playwright, so those pages are rendered in a real browser before your spider parses them. The rest of the crawl keeps using Scrapy's fast HTTP downloader.
What is Scrapyd?
An open-source service that runs Scrapy spiders on a server and lets you schedule, start and stop them through an HTTP API. It is a common way to run spiders in production without a separate job platform.
Related pages
Easy Trial: 1 GB for $2.95.
Try for the price of 1 GB, no subscription, traffic never expires.