Guides

Proxies for Web Scraping: A Practical Guide

Proxies are what let a scraper run at scale without getting blocked. The idea is simple — spread requests across many IPs so no single address looks abusive — but doing it well takes a few deliberate choices. Here's the practical version, without the hype.

Why scrapers need proxies

Send a few thousand requests from one IP and a reasonably defended site will likely rate-limit or ban it. Proxies distribute that traffic so no single IP carries all of it. They also let you collect geo-specific data by choosing where requests originate.

1. Pick the right proxy type

Match the proxy to the target's defenses, not to your budget's ceiling:

  • Datacenter — start here for tolerant targets. Cheap, fast, plentiful.
  • Residential — switch to these for sites with real anti-bot defenses; their IPs look like ordinary households.

The full trade-off is in Residential vs Datacenter Proxies. A good rule: default to datacenter, escalate to residential only for the targets that block you.

2. Rotate — but not blindly

Use rotation for independent page fetches, and sticky sessions for any multi-step flow (login, cart, pagination with cookies). The classic mistake is rotating on every connection, which makes a single page load — with its dozens of sub-requests — look like one user hopping across many IPs. Keep one logical page on one IP, then rotate. Details in What Is a Rotating Proxy? and Sticky vs Rotating Sessions.

3. Pace your requests

Proxies hide your IP; they don't hide inhuman behavior. Add delays, randomize them, and cap concurrency per target. A scrape that hammers a site as fast as possible will trip rate limits no matter how many IPs you have. Slower and complete beats fast and blocked.

4. Look like a real client

  • Send a realistic, consistent User-Agent and accompanying headers.
  • Keep headers coherent with the “browser” you're claiming to be.
  • Handle cookies within a session so stateful flows stay consistent.
  • Let the proxy resolve DNS to avoid leaks — an HTTP proxy does this by design; with SOCKS, use socks5h://.

5. Handle failures gracefully

Expect some requests to fail — a blocked IP, a timeout, a CAPTCHA. Always set a timeout, retry a bounded number of times with backoff, detect block pages (not every block is an HTTP 4xx — many return a 200 with a challenge body), and log which targets are getting hard. Every retry that gets a response moves bytes, and per-GB proxies bill them.

A minimal example

Routing Python requests through a rotating proxy endpoint:

import random, time
import requests

PROXY = "http://USER:PASS@HOST:PORT"
UA = "Mozilla/5.0 ..."             # a real, current browser UA
urls = ["https://example.com/page/1", "https://example.com/page/2"]

s = requests.Session()
s.proxies = {"http": PROXY, "https": PROXY}
s.headers["User-Agent"] = UA

failed = []
for url in urls:
    ok = False
    for attempt in range(3):
        try:
            r = s.get(url, timeout=(5, 30))
            if r.status_code == 200 and "captcha" not in r.text.lower():
                print(url, len(r.text))      # save(r.text) in real code
                ok = True
                break
            if r.status_code not in (200, 429, 500, 502, 503, 504):
                break                        # 403/404: retrying won't help
        except requests.RequestException:
            pass
        time.sleep(2 ** attempt + random.random())   # backoff
    if not ok:
        failed.append(url)                   # revisit later
    time.sleep(random.uniform(1.5, 4.0))     # pacing between pages

Step-by-step setups for Python requests, Scrapy, Playwright, and Selenium cover the details; the setup guide covers browsers and curl.

Scrape responsibly

Respect robots.txt where it applies, don't overload small sites, and stay within the law and the target's terms. Proxies are a reliability tool, not a license to ignore a site's rules.

The setup in one place

o2co puts datacenter and residential exits behind one proxy endpoint that speaks HTTP and SOCKS5 on the same port. The gateway picks the exit per connection: the plain username keeps a burst of requests on one exit, and -rotate on the username gives every new connection a different exit (per connection, not per request, so a pooled connection keeps its exit); sticky mode for longer multi-step flows is set on your account on request; the country goes on the username as -country-xx. Billing is per GB, from a plan quota or a data balance that never expires. Get 1 GB free and point a test scrape at it, or see pricing.