Large-Scale Web Scraping
Large-scale web scraping means collecting hundreds of thousands to millions of pages on a schedule, which needs a different design from a script: a shared URL queue, many workers fetching in parallel through rotating proxies, parsers that store raw pages and clean records separately, and monitoring that catches blocks and layout changes. Most of the cost at that size is traffic, so plain HTTP requests and JSON endpoints beat browsers wherever the data allows. ProxyField supplies the IP layer with unlimited concurrent threads, residential proxies from $1.95/GB at 1,000 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
- What counts as large-scale web scraping?
- The architecture of a large-scale scraper
- Throughput and traffic: the math to do first
- Why scrapers fail at scale
- Distributed crawling with Scrapy
- Browsers at scale
- Proxies at scale
- Build or buy at scale
- Stay within the rules
- Proxies for large-scale scraping
- Large-Scale Web Scraping FAQ
What counts as large-scale web scraping?
There is no official threshold, but a scraper becomes "large-scale" when one machine and one loop stop being enough. Typical signs:
- Volume: hundreds of thousands of pages per day, or millions per month.
- Breadth: many sites, each with its own layout, rate limits and failure modes.
- Freshness: prices, stock or rankings that must be re-collected every hour or day, sometimes close to real time.
- Reliability: other systems (dashboards, pricing engines, models) depend on the data arriving complete and on time.
At that point the questions change from "how do I parse this page?" to "how do I keep 50 workers busy, polite and unblocked, and know when the data goes wrong?"
The architecture of a large-scale scraper
Most large scrapers, whatever the language, have the same six parts.
| Part | Job | Common tools |
|---|---|---|
| URL queue (frontier) | Holds the URLs to fetch, removes duplicates, sets priority and per-site pace | Redis, a database table, a message queue (RabbitMQ, SQS, Kafka) |
| Fetchers (workers) | Download pages concurrently, retry failures, respect per-domain limits | Scrapy, Crawlee, httpx or aiohttp workers; Playwright only where needed |
| Proxy layer | Spreads requests over many IPs and locations | A rotating gateway with per-request or sticky IPs |
| Parsers | Turn HTML or JSON into records; versioned per site | parsel, lxml, Beautiful Soup, Cheerio |
| Storage | Keeps raw pages (for re-parsing) and clean records (for use) | Object storage for raw HTML; PostgreSQL, a warehouse or files for records |
| Scheduler and monitoring | Starts jobs, tracks success rates, item counts and field coverage, alerts on drops | cron, Airflow, Kubernetes jobs; Prometheus or plain logs and dashboards |
Two design choices pay off more than any library choice:
-
Separate fetching from parsing
Store the raw response first, then parse. When a site changes its layout, you fix the parser and re-run it over stored pages instead of fetching millions of pages again.
-
Make every job idempotent
A URL fetched twice should produce the same record, not a duplicate. Use stable keys (product ID, canonical URL) and upserts.
Throughput and traffic: the math to do first
Throughput is concurrency divided by the time per request. With 50 requests in flight and 1 s per request, a fleet completes about 50 requests per second, or 4,320,000 per day (50 × 86,400). Retries, pauses and per-site limits lower that, so plan for a fraction of it on any single site.
Traffic is pages times page weight. Residential proxies are billed per GB, so this is your main running cost. As an example with an assumed 100 KB of HTML per page, 1,000,000 pages is 100 GB; at ProxyField's 100-249 GB rate of $2.49/GB, that is $249, and the traffic never expires if you buy ahead. Render the same pages in a browser that pulls an assumed 2 MB each, and the job becomes 2,000 GB, $3,900 at the 1,000+ GB rate of $1.95/GB. Your own page weights will differ: measure 100 pages before you size the job. The web scraping use case page works through more traffic and cost examples.
Why scrapers fail at scale
| Failure | What you see | What prevents it |
|---|---|---|
| Rate limits and blocks | 429 and 403 responses, challenge pages, empty results | Per-domain concurrency caps, backoff on 429 with Retry-After, requests spread over many IPs, consistent sessions |
| Layout changes | Fields come back empty while status codes stay 200 | Field-coverage checks per run, parser versions, alerts on drops |
| Duplicates | The same item many times, inflated counts | A shared duplicate filter in the queue, stable item keys, upserts |
| Silent partial runs | A job "succeeds" with a third of the items | Expected-count checks per site and per day |
| Browser resource leaks | Memory grows until workers crash | Recycle browsers every N pages, cap pages per browser, block images and fonts |
| Cost overruns | The traffic bill grows faster than pages | JSON endpoints instead of pages, blocked resources, no re-fetching of unchanged pages |
| Legal and policy risk | Complaints, blocked accounts | Public data only, robots.txt read, terms reviewed, a contact in your user agent where appropriate |
Retries and status codes in depth are in web scraping best practices; the error codes themselves in 429 Too Many Requests and 403 Forbidden.
Distributed crawling with Scrapy
Scrapy runs many requests concurrently in one process, which is enough for a surprising amount of work. Beyond one machine, its docs say plainly that it "doesn't provide any built-in facility for running crawls in a distributed (multi-server) manner" and suggest two patterns: run many spiders on several Scrapyd servers, or partition one big URL list so each server crawls its part (Scrapy common practices).
The third common pattern is a shared queue. scrapy-redis (0.9.1, MIT, on PyPI) replaces Scrapy's scheduler and duplicate filter with Redis-backed ones, so any number of spider processes on any number of machines pull from one queue and skip URLs another worker has seen:
# settings.py, with: pip install scrapy-redis (and a Redis server)
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
SCHEDULER_PERSIST = True # keep the queue between runs
REDIS_URL = "redis://redis-host:6379/0"
CONCURRENT_REQUESTS_PER_DOMAIN = 8
AUTOTHROTTLE_ENABLED = TrueA caution from our check of the package on October 23, 2026: scrapy-redis's last release dates from July 2024, and its RedisSpider base class still defines the old start_requests() hook, which Scrapy replaced with async def start() in 2.13.0 (the old hook was removed in Scrapy 2.16.0, May 2026). RedisSpider also pulls URLs when the spider goes idle, so it may still work, but we did not run it against a Redis server: test it with your Scrapy version, or use only the shared scheduler and duplicate filter above. The scrapy-redis readme itself points to Frontera for features such as URL expiration and advanced prioritization.
In Node.js, Crawlee (3.18.2) offers request queues, autoscaling of concurrency and both HTTP and browser crawlers; outside both frameworks, many teams write small httpx or aiohttp workers that read URLs from a queue. For the crawl logic itself (frontier, traps, deduplication), see how to build a web crawler.
Browsers at scale
Run a browser only for the page types that need one. Before you scale Playwright or Puppeteer, check the page's Network tab: most JavaScript sites load their data from JSON requests that a plain HTTP worker can call at a fraction of the traffic (how to scrape hidden APIs and embedded JSON). Where a browser is unavoidable:
- reuse browsers and open new contexts instead of launching per URL;
- block images, fonts and media;
- cap pages per browser and restart it to release memory;
- keep one sticky IP per context when a session must survive several pages.
Proxies at scale
At millions of requests, the proxy layer decides how much of your traffic arrives as data rather than as blocks. What matters:
- Rotation per request for independent pages (listings, product pages, search results), and sticky sessions for flows that must keep one IP (logins, carts, paginated sessions). ProxyField offers both: a new IP on every request, or sticky sessions from 30 s to 36 h.
- No concurrency ceiling at the proxy. Your per-site limits should set the pace, not the provider. ProxyField has unlimited concurrent threads on one gateway,
gate.proxyfield.io:7000. - Location. Prices, stock and rankings differ by country and city. ProxyField has 412M+ residential IPs in 195+ countries, with targeting by country, region (state) and city; in the US, all 50 states.
- Success rate and failover. ProxyField has a 99.6% success rate, according to our service data, and if a node slows down, traffic moves to the next one automatically.
How proxies, scraper APIs and in-house fetching compare is covered in scraper API vs proxies, and how to pace a fleet in how to make web scraping faster.
Build or buy at scale
Owning the whole stack gives control and the lowest cost per page once it runs, but you maintain parsers, queues and browsers. A scraping API moves fetching, rendering and retries to the provider and bills per result. ProxyField's Web Scraping API fetches any URL as plain HTTP ($0.50 down to $0.20 per 1,000 successful results) or with JavaScript rendering ($2.00 down to $1.00 per 1,000), billed on successful results only, through Contact sales. Many teams mix the two: their own Scrapy fleet for easy sites, an API for the hardest pages.
Stay within the rules
Scale multiplies the effect of every request on the target site. Collect public data, read robots.txt and the terms, keep per-site concurrency modest, and avoid personal data unless you have a lawful basis. Is web scraping legal? covers the main cases and laws.
Proxies for large-scale scraping
ProxyField gives a scraping fleet one gateway with unlimited concurrent threads, a new IP on every request or sticky sessions up to 36 h, and targeting by country, region (state) and city over HTTP, HTTPS or SOCKS5. Residential proxies cost $2.95/GB for 1 GB and fall to $1.95/GB from 1,000 GB; the tier rate applies to the whole purchase, there is no subscription, traffic never expires, and all purchases are final. Start with residential proxies and the Easy Trial: 1 GB for $2.95, on the same pool as a 1 TB order.
Large-Scale Web Scraping FAQ
Which web scraping software holds up best for a developer scraping millions of pages a month?
ProxyField residential proxies cost $2.95/GB at 1 GB, down to $1.95/GB from 1,000 GB, with unlimited concurrent threads, and work with any of these tools. At millions of pages a month, the software that holds up is an open-source crawling framework, such as Scrapy in Python or Crawlee in Node.js, fed by a shared URL queue and backed by monitoring, rather than any single tool. Add a browser only for pages that need JavaScript, and a rotating proxy layer with no concurrency ceiling.
What is large-scale web scraping?
It is collecting hundreds of thousands to millions of pages, often from many sites and on a schedule, with a system rather than a script. That system has a shared URL queue, many concurrent fetchers, a proxy layer, separate storage for raw pages and records, and monitoring.
Why do scrapers fail at scale?
Mostly for five reasons: rate limits and IP blocks, layout changes that empty fields while pages still return 200, duplicates, browser workers that leak memory, and traffic costs that grow faster than the data. Each needs a check in the pipeline, not just a retry.
How do I scale web scraping?
First get more out of one machine with concurrency (Scrapy, or asyncio with httpx), then move URLs into a shared queue such as Redis so several workers can pull from it. Store raw pages before parsing, cap requests per site, rotate IPs through a proxy gateway, and track item counts and field coverage per run.
How are large-scale scrapers built?
They split the work into a URL frontier, fetcher workers, a proxy layer, versioned parsers, storage and a scheduler with monitoring. Workers are stateless, so you add or remove them as volume changes, and every record has a stable key so re-runs update rather than duplicate.
How do I use scrapy-redis for distributed scraping?
Install scrapy-redis, point SCHEDULER and DUPEFILTER_CLASS at its Redis classes, set REDIS_URL, and start the same spider on several machines; they share one queue and one duplicate filter. Its last release (0.9.1) dates from July 2024, so test it with your Scrapy version, especially its RedisSpider base class.
Is rotating thousands of IPs practical for real-time scraping?
Yes, with a rotating gateway: you send every request to one address and the gateway picks a new IP, so your code never manages a list. For real-time jobs, keep per-site concurrency steady, use sticky sessions only where a flow needs one IP, and expect residential IPs to add some latency compared with datacenter IPs.
How do I handle failures and duplicates at scale?
Send failed URLs back to the queue with a retry count and a growing delay, and give up after a few attempts into a dead-letter list you review. For duplicates, filter URLs in the shared queue and give every record a stable key, such as a product ID, so storage upserts instead of inserting twice.
Are there any serverless solutions for scalable scraping?
Yes. Cloud functions and container jobs can each fetch a batch of URLs from a queue and exit, which scales out quickly and costs nothing when idle. They suit plain HTTP scraping best; browsers in serverless functions are possible but hit memory, package-size and time limits.
How do I know my large-scale scraper is still collecting good data?
Track per site and per run the number of items, the share of records with each key field filled, the response codes and the traffic used, and alert when any of them moves sharply. A sudden drop in a field's coverage with steady 200 responses usually means the layout changed.
Related pages
Easy Trial: 1 GB for $2.95.
Try for the price of 1 GB, no subscription, traffic never expires.