# 403, 429 en CAPTCHAs: reageer, vermijd niet

> Hoe om te gaan met 403, 429 en CAPTCHAs bij scrapen: wat elk signaal betekent, een beleefde Python crawler met robots.txt en Retry-After, en wat je beter niet kunt doen.

- URL: https://crawlrelay.com/nl/guides/403-429-captcha/
- Laatst bijgewerkt: 2026-10-13
- Publisher: CrawlRelay (https://crawlrelay.com)

Een 403, een 429 of een CAPTCHA is een signaal van een site aan je crawler. Het juiste antwoord is vrijwel altijd om te vertragen, de regels te lezen of om toestemming te vragen; het verkeerde antwoord is het verbergen van de crawler. Zo bouw je het juiste antwoord in de code.

**Kort antwoord — Hoe moet een scraper omgaan met 403, 429 en CAPTCHA-responses?**

Behandel ze als signalen, niet als obstakels. Bij een **429** wacht je `Retry-After` en verlaag je je snelheid op die host. Bij een **403** probeer je het nog één keer na een pauze, stop dan en controleer de regels van de site. Bij een **CAPTCHA** stop je die host: los het niet automatisch op. **CrawlRelay residentiële proxy's**, van US$ 0,50/GB, spreiden de belasting en zetten de locatie; ze omzeilen niet het besluit van een site. Zonder KYC. Betaal in crypto.

## De drie signalen in één oogopslag

| Attribuut | Waarde |
| --- | --- |
| 429 Te Veel Verzoeken | Je bent te snel. Houd je aan Retry-After, doe een stapje terug, verlaag het aantal gelijktijdige verbindingen per host |
| 403 Forbidden | Dit verzoek wordt geweigerd. Eén keer opnieuw proberen na een pauze, dan stoppen en regels nakijken |
| CAPTCHA of challenge-pagina | De site wil weten of je een mens bent. Stop de host en vertraag |
| Standaard voor crawlregels | robots.txt, RFC 9309; Crawl-delay is een veelgebruikte uitbreiding |
| Wat wij niet ondersteunen | CAPTCHA oplossen, stealth-plugins, vingerafdrukvervalsing |

## Wat zegt elk signaal mijn crawler?

- **429** is het beleefdst: de content is beschikbaar, maar niet op jouw tempo. RFC 6585 definieert het, vaak met een `Retry-After` header die zegt wanneer je terug mag komen.
- **403** is een weigering van dit verzoek. Dit kan opgelost worden (verkeerd land, ontbrekende headers, te snel) of definitief (de site staat geen geautomatiseerde toegang tot die content toe).
- **Een CAPTCHA of challenge-pagina**, vaak met status 403 of 503, betekent dat het botbeheer van de site je verkeer betwijfelt. Het is een escalatie: de stap na genegeerde 429's.

Alle drie zijn oplopende signalen. Sites die zien dat hun 429s genegeerd worden, escaleren naar 403s en challenges, en daarna tot langdurige blokkades van hele IP-bereiken, wat elke gebruiker van die bereiken raakt.

## Wat moet mijn crawler doen bij elk signaal?

| Signaal | Eerste reactie | Als het doorgaat | Stop wanneer |
| --- | --- | --- | --- |
| 429 | Wacht op Retry-After of doe een exponentiële back-off met jitter | Halveer het aantal gelijktijdige verbindingen op die host | Retry-After wordt steeds langer, of 429s blijven bij één verzoek tegelijk |
| 403 | Één herhaling na een pauze, zelfde land | Vergelijk met een browser uit hetzelfde land; controleer robots.txt en voorwaarden | Een tweede 403 op hetzelfde URL-patroon |
| CAPTCHA / challenge | Pauzeer die host enkele minuten | Hervat met een veel lagere snelheid | De challenge komt terug bij lage snelheid: de site wil geen geautomatiseerde toegang |
| 503 met Retry-After | Wacht zoals gevraagd | Pauzeer die host | De meeste verzoeken falen langer dan een paar minuten |

## Hoe bouw ik een crawler die juist reageert?

Zet de regels in de fetcher, niet in elke spider. Deze stuurt één verzoek tegelijk per host, respecteert robots.txt en de `Crawl-delay`, wacht op `Retry-After`, en stopt met vragen aan een host na drie weigeringen op rij. Hij behandelt een 4xx robots.txt als toestemming en een 5xx als een volledige weigering, zoals RFC 9309 voorschrijft.

*Python: een beleefde fetcher*

```python
import time
import urllib.robotparser
from urllib.parse import urlsplit

import requests

PROXY = "http://USERNAME-country-us:PASSWORD@gw.crawlrelay.com:7777"
USER_AGENT = "ExampleCrawler/1.0 (+https://example.com/crawler-info)"


class PoliteFetcher:
    """One request at a time per host; robots.txt, Crawl-delay and Retry-After honoured."""

    def __init__(self, min_interval=1.0, max_refusals=3):
        self.min_interval, self.max_refusals = min_interval, max_refusals
        self.http = requests.Session()
        self.http.proxies = {"http": PROXY, "https": PROXY}
        self.http.headers["User-Agent"] = USER_AGENT
        self.robots, self.next_time, self.refusals = {}, {}, {}

    def _robots(self, root):
        if root not in self.robots:
            rp = urllib.robotparser.RobotFileParser(root + "/robots.txt")
            try:
                r = self.http.get(root + "/robots.txt", timeout=(10, 30))
                if r.status_code >= 500:
                    rp.parse(["User-agent: *", "Disallow: /"])  # unreachable: assume disallow
                else:
                    rp.parse(r.text.splitlines() if r.status_code == 200 else [])  # 4xx: allowed
            except requests.RequestException:
                rp.parse(["User-agent: *", "Disallow: /"])
            self.robots[root] = rp
        return self.robots[root]

    def get(self, url):
        scheme, host = urlsplit(url)[:2]
        if self.refusals.get(host, 0) >= self.max_refusals:
            return None  # this host said no: stop asking
        rp = self._robots("%s://%s" % (scheme, host))
        if not rp.can_fetch(USER_AGENT, url):
            return None
        delay = max(self.min_interval, rp.crawl_delay(USER_AGENT) or 0)
        wait = self.next_time.get(host, 0) - time.monotonic()
        if wait > 0:
            time.sleep(wait)
        r = self.http.get(url, timeout=(10, 30))
        pause = delay
        if r.status_code in (429, 503):
            retry_after = r.headers.get("Retry-After", "")
            pause = max(delay, int(retry_after) if retry_after.isdigit() else 60)
        refused = r.status_code in (403, 429) or "captcha" in r.text[:5000].lower()
        self.refusals[host] = self.refusals.get(host, 0) + 1 if refused else 0
        self.next_time[host] = time.monotonic() + pause
        return r


fetcher = PoliteFetcher()
resp = fetcher.get("https://example.com/")
print(resp.status_code if resp is not None else "skipped")
```

## Wat lost een 403 legitiem op?

Meerdere oorzaken van een 403 liggen aan jouw kant en het oplossen hiervan is terecht:

- **Het verkeerde land.** Veel sites serveren per regio. Richt je op het land met `-country-<code>`.
- **Onvolledige headers.** Stuur `Accept`, `Accept-Language` en een eerlijke user agent met een contact-URL. Een browserachtige user agent op een gewone HTTP-client is inconsistent en wordt vaak geweigerd.
- **Je eigen tempo.** Een 403 die begint na N verzoeken is een snelheidsprobleem; vertraag.

Wat geen oplossing is: user agents rouleren om eruit te zien als veel verschillende mensen, browser-vingerafdrukken spoofen of IP's wisselen om een door de site bewust ingestelde blokkade te omzeilen. Als een site hosting-bereiken filtert om geautomatiseerd verkeer buiten te houden, maakt een residentiële proxy dat die toegang niet toegestaan is.

## Waarom niet gewoon de CAPTCHAs oplossen?

Omdat een CAPTCHA de site is die je een vraag stelt waarop je verkeerd zou antwoorden. Geautomatiseerd oplossen verandert een beleefde crawler in een tool die is gemaakt om een toegangscontrole te omzeilen, wat je juridische risico verhoogt: de Amerikaanse zaken van 2026 over zoek-scraping, Google tegen SerpApi en Reddit tegen SerpApi en anderen, draaien om de bewering dat gedaagden een anti-bot systeem omzeilden onder de DMCA anti-omzeilingsregel. De rechtbanken hebben de vraag nog niet beslecht, maar het risico is reëel.

CrawlRelay ondersteunt geen CAPTCHA-oplossing of ontduiking van bot-detectie, en het [Acceptable Use Policy](https://crawlrelay.com/nl/acceptable-use/) verbiedt dit via de gateway. Als je data achter een challenge nodig hebt, vraag dan toegang aan bij de site, gebruik de API, of licentieer de data.

## Wanneer moet ik de site in plaats daarvan contacteren?

Wanneer je meer nodig hebt dan de standaardinstellingen toestaan. Veel sites bieden een API, een datafeed, een partnerprogramma of gewoon een hogere limiet voor een crawler die zich identificeert en zijn doel uitlegt. Voeg een contact-URL toe in je user agent, houd een pagina bij die jouw crawler beschrijft en uitlegt hoe je jezelf kunt afmelden, en beantwoord misbruikrapporten snel. Een crawler die bereikbaar is, krijgt waarschuwingen vóór blokkades.

## 403, 429 en CAPTCHAs: vragen

### Stoppen residentiële proxy's CAPTCHAs?

Vertrouw er niet op. Een residentieel exit verandert welk IP een site ziet, niet wat jouw crawler doet: CAPTCHAs veroorzaakt door je tempo of gedrag blijven, en dat is de bedoeling. Als challenges blijven komen bij een laag verzoektempo, wil de site geen geautomatiseerde toegang tot die inhoud.

### Hoe lang moet ik wachten na een 429 zonder Retry-After?

Begin met enkele seconden en verdubbel de wachttijd na elke nieuwe 429, met een willekeurige toevoeging en een maximum van ongeveer een minuut. Als de verzoeken weer slagen, hervat dan met een lager tempo dan degene die de 429 veroorzaakte, en verhoog het langzaam terwijl het foutpercentage constant blijft.

### Is het toegestaan om IP-adressen te rouleren om snelheidslimieten te vermijden?

Rotatie verdeelt de belasting over exits en laat je locaties kiezen, wat normaal is. Roteren om onder een per-IP limiet te blijven terwijl je een tempo aanhoudt dat de site weigerde, is omzeiling. De meeste gebruiksvoorwaarden verbieden dit, en zo ook ons Acceptable Use Policy.

### Welke user agent moet mijn scraper meesturen?

Je eigen: een naam, een versie en een URL die uitlegt wat de crawler is en hoe je contact opneemt, zoals `ExampleCrawler/1.0 (+https://example.com/crawler-info)`. Gebruik geen namen van andere crawlers zoals Googlebot of GPTBot.

## Bronnen

1. [RFC 9309: Robots Exclusion Protocol](https://www.rfc-editor.org/rfc/rfc9309.html) — IETF (2022-09)
2. [RFC 6585: Additional HTTP Status Codes (429)](https://www.rfc-editor.org/rfc/rfc6585) — IETF (2012-04)
3. [Reddit tegen SerpApi LLC](https://www.loeb.com/en/insights/publications/2026/08/reddit-v-serpapi-llc) — Loeb & Loeb (2026-08)
4. [Google tegen SerpApi: de rechtbank wees onze motie tot verwerping toe](https://serpapi.com/blog/google-v-serpapi-the-court-granted-our-motion-to-dismiss/) — SerpApi (2026-07-21)

**Residentiële proxy's voor beleefde crawlers** US$ 1,50 voor 1 GB, US$ 0,50/GB vanaf 50 GB. [Zie prijslijst](https://crawlrelay.com/nl/pricing/) · [Foutreferentie](https://crawlrelay.com/nl/docs/errors/)

---

CrawlRelay: CrawlRelay is een developer-first dienst met roterende residentiële proxy's en mobiele 4G-proxy's voor scrapers en AI-datastromen: niet-vervalverkeer op basis van pay-as-you-go vanaf US$ 0,50/GB, betaald in crypto, zonder ID-upload. Zonder KYC — geen ID, geen selfie, geen documenten. Betaal met crypto.
