DEV Community

pante5ter
pante5ter

Posted on

3 Reasons Your Web Scraper Breaks in Production (and How to Fix Each)

Most scrapers work great on your laptop and then quietly fall apart the moment they run unattended. The script that pulled 10,000 rows in a demo returns 12 rows at 3 a.m. and nobody notices for a week. After shipping a fair number of these for clients, the failure modes are almost always the same three. Here's how to make a scraper that survives real sites.

1. No retries

The single most common reason a scraper dies: one network timeout kills the entire run.

Real sites are flaky. A request that succeeds 99% of the time will still fail several times across a 10,000-page job — and if a single failure throws an uncaught exception, you lose the whole run, not one row.

The fix is retries with exponential backoff. Wrap each request, retry a few times with growing delays, and log what failed so you can inspect it later. You want to lose a row, not the job.

import time

def fetch(url, retries=3, backoff=2):
    for attempt in range(retries):
        try:
            return get(url)
        except TransientError as e:
            if attempt == retries - 1:
                log.warning("giving up on %s: %s", url, e)
                return None
            time.sleep(backoff ** attempt)
Enter fullscreen mode Exit fullscreen mode

2. Hard-coded selectors with no fallback

Sites change their markup constantly. A scraper built around div.price-box > span.amount will silently return empty strings the day the site ships a redesign — and silent failure is the worst kind, because your pipeline keeps running on garbage data.

Two things make this survivable: use resilient selectors (prefer stable attributes like data-* or itemprops over deeply nested class chains), and validate what you extract. If a field that should always be present comes back empty, raise a clear error instead of writing a blank. A loud failure is a 5-minute fix; a silent one is a corrupted dataset.

3. No rate-limit or proxy handling

Hit a site too fast and you get blocked — IP ban, CAPTCHA wall, or throttling that quietly drops your success rate. A scraper with no pacing isn't faster, it's just banned sooner.

Add human-like delays between requests, respect robots.txt and any documented limits, and rotate proxies/user-agents for larger jobs. The goal is to keep collecting data steadily rather than burning your access in the first ten minutes.

The pattern underneath all three

Each fix is the same idea: assume the outside world is hostile and design for failure. Retries handle flaky networks, validation handles changing markup, and pacing handles defensive servers. A scraper that does these three things runs unattended for months; one that skips them needs a babysitter.


I build scrapers, automation and Telegram bots that hold up in production — clean, typed code you own. If you've got a scraping or automation job (or a scraper that keeps breaking), see my work here: https://vengstudio-portfolio.vercel.app

VENG STUDIO — code that comes alive.

Top comments (0)