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
| 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-Afterheader 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.
import time
import urllib.robotparser
from urllib.parse import urlsplit
import requests
PROXY = "http://USERNAME-country-us:[email protected]: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-Languageen 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 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 (4)
- RFC 9309: Robots Exclusion Protocol — IETF (2022-09)
- RFC 6585: Additional HTTP Status Codes (429) — IETF (2012-04)
- Reddit tegen SerpApi LLC — Loeb & Loeb (2026-08)
- Google tegen SerpApi: de rechtbank wees onze motie tot verwerping toe — SerpApi (2026-07-21)
Residentiële proxy's voor beleefde crawlers
US$ 1,50 voor 1 GB, US$ 0,50/GB vanaf 50 GB.