403 Forbidden im Web Scraping: Die Lösung, die tatsächlich funktioniert
Ein 403 ist kein Berechtigungsproblem – es ist ein Erkennungsproblem. Vier Sprossen trennen ein blockiertes Skript von einem 200, und die meisten Menschen hören bei der ersten auf.
Ein 403 Forbidden-Fehler im Web Scraping bedeutet fast nie, was der Statuscode sagt. HTTP 403 wird definiert als der Server versteht Ihre Anfrage und verweigert die Autorisierung – aber wenn es einen Scraper trifft, hat es selten etwas mit Berechtigungen oder einem fehlenden Login zu tun. Es bedeutet, dass die Seite Ihre Anfrage angesehen hat, entschieden hat, dass sie von einer Maschine gesendet wurde, und die Tür geschlossen hat. Das sagt Ihnen, was Sie ändern müssen: nicht Ihre Anmeldedaten, sondern die Form Ihres Datenverkehrs. Unten ist die Lösungssprosse, die günstigste zuerst, mit den Prüfungen, die identifizieren, auf welcher Sprosse Sie feststecken.
403 vs 401 vs 429: was jeder Ihnen sagt
Stellen Sie die richtige Diagnose, bevor Sie Code schreiben. Ein 401 Unauthorized verlangt Anmeldedaten – deren Bereitstellung behebt es. Ein 403 Forbidden verweigert unabhängig von Anmeldedaten, sodass das Einloggen nichts ändert, wenn die Bot-Erkennung ausgelöst wurde. Ein 429 Too Many Requests betrifft das Volumen und klärt sich, wenn das Fenster zurückgesetzt wird; ein 403 betrifft die Identität und bleibt bestehen, bis Sie ändern, wie Ihre Anfrage aussieht. Wenn Ihr Scraper 429s statt 403s erhält, ist die Lösung das Timing, nicht die Tarnung – das behandeln wir in Behebung von 429 Too Many Requests.
Diagnose in 60 Sekunden, bevor Sie Code ändern
Drei Befehle sagen Ihnen fast alles. Führen Sie die nackte Anfrage aus, führen Sie sie erneut mit nur einem Browser User-Agent ausgetauscht aus und lesen Sie dann den Antwortkörper – der Blockierungsgrund ist normalerweise darin geschrieben.
# 1. Bare request: what does the target give a naked client?
curl -sS -o /dev/null -w '%{http_code}\n' https://target.example/page
# 2. Same request, browser User-Agent only
curl -sS -o /dev/null -w '%{http_code}\n' \
-A 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36' \
https://target.example/page
# 3. Read the body and the response headers - the reason is in there
curl -sS -D - https://target.example/page | head -c 600
Interpretieren Sie es so. Wenn Schritt 2 200 zurückgibt, liegt das gesamte Problem bei den Headern und Sie sind bei Sprosse 1 fertig. Wenn der Körper Cloudflare, eine Ray-ID oder Fehler 1020 erwähnt, befinden Sie sich hinter einer WAF-Regel – siehe Cloudflare-Fehler 1020. Eine einfache Apache- oder nginx-Forbidden-Seite bedeutet normalerweise ein Servermodul wie mod_security, das bekannte Bot-User-Agents blockiert hat, lange bevor moderne Bot-Management existierte. Und wenn ein Browser auf derselben Maschine die Seite lädt, während Ihr Client dies nicht tut, arbeiten Sie sich durch curl 403 aber der Browser funktioniert.

Sprosse 1: hören Sie auf, sich in den Headern zu verraten
Pythons urllib identifiziert sich als etwas wie python-urllib/3.3.0; requests sendet python-requests/2.x. Diese Zeichenfolgen sind ein Geständnis, und die am meisten hochgestimmte Antwort auf den kanonischen Stack Overflow-Thread über 403s im Python-Scraping ist einfach: senden Sie stattdessen einen Browser User-Agent. Das funktioniert immer noch auf vielen Seiten. Aber zwei Dinge haben sich geändert, seit diese Antwort geschrieben wurde. Erstens ist ein nacktes Mozilla/5.0 jetzt selbst eine Flagge – Kommentatoren auf demselben Thread berichten, dass Seiten es direkt blockieren, weil kein echter Browser einen zwei-Token-UA sendet. Zweitens vergleichen moderne Server Ihr gesamtes Header-Set, nicht nur ein Feld.
Senden Sie ein kohärentes Set: einen aktuellen Browser-UA, die passende Accept-Kette, eine Sprache und die Sec-Fetch-*-Metadaten-Header, die Chromium zu jeder Navigation hinzufügt. Die Reihenfolge der Header ist auch bei strengeren Zielen wichtig – verwenden Sie eine geordnete Zuordnung und setzen Sie sie in die Reihenfolge, die ein Browser verwendet.
import requests
HEADERS = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
),
"Accept": (
"text/html,application/xhtml+xml,application/xml;q=0.9,"
"image/avif,image/webp,*/*;q=0.8"
),
"Accept-Language": "en-GB,en;q=0.9",
"Accept-Encoding": "gzip, deflate", # add 'br' only if brotli is installed
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
"Connection": "keep-alive",
}
with requests.Session() as s:
s.headers.update(HEADERS)
r = s.get("https://target.example/page", timeout=20)
print(r.status_code, len(r.content))
Eine Kohärenzfalle fängt fast jeden: ein UA, der einen US-Chrome-Desktop behauptet, gepaart mit Accept-Language: de-DE und einer Exit-IP in Brasilien, ist ein Missverhältnis, das jedes anständige System bemerkt. Halten Sie User-Agent, Sprache und IP-Geografie in Einklang.
Einige 403s auf dieser Sprosse sind noch einfacher: ein fehlender Referer. Server, die ein Asset nur dann bereitstellen, wenn die Anfrage aussieht, als käme sie von ihrer eigenen Seite, geben 403 bei einem direkten Treffer zurück und 200 in dem Moment, in dem Sie die verweisende URL hinzufügen. Es ist ein Klassiker und kostet einen Header zum Testen.
Sprosse 2: der TLS-Fingerprint, den Header nicht beheben können
Wenn perfekte Header immer noch 403 zurückgeben, ist die Blockierung erfolgt, bevor Ihre Header überhaupt gelesen wurden. Jeder HTTPS-Client kündigt seine Cipher-Suites, Erweiterungen, elliptischen Kurven und ALPN im TLS ClientHello an, und diese Kombination hasht sich in einen JA3- oder JA4-Fingerprint. Pythons requests, Gos net/http und Standard-curl haben jeweils einen markanten, den kein Anti-Bot-Anbieter mit Chrome verwechselt. Sich in einem Header als Chrome 131 auszugeben, während man wie OpenSSL handshaked, ist der lauteste Widerspruch, den ein Scraper machen kann.
Die Lösung ist ein Client, der sich auf der TLS-Ebene als echter Browser ausgibt. In Python ist das curl_cffi, eine Bindung an ein gepatchtes libcurl, das Browser-ClientHellos reproduziert:
# pip install curl_cffi
from curl_cffi import requests as cffi
proxy = "http://USER:PASS@gate.quantumproxies.io:8000"
r = cffi.get(
"https://target.example/page",
impersonate="chrome", # Chrome JA3/JA4 + HTTP/2 settings
proxies={"http": proxy, "https": proxy},
timeout=20,
)
print(r.status_code)
Node hat Äquivalente, die auf denselben gepatchten TLS-Stacks aufgebaut sind. Wenn Sie die vollständige Mechanik wissen möchten, warum diese einzelne Änderung einen 403 auf einen 200 auf geschützten Seiten umschaltet, lesen Sie wie JA3/JA4-Fingerprinting Ihren Scraper verrät.
Sprosse 3: die IP ist die Botschaft
Header und TLS beschreiben den Client. Die IP beschreibt, wer fragt, und sie wird stark gewichtet. Adressen in Hosting- und Cloud-Bereichen sind veröffentlicht, leicht nach ASN zuzuordnen und tragen einen niedrigeren Vertrauensscore, bevor ein einziges Byte Ihrer Anfrage inspiziert wird – weshalb ein Scraper auf einem VPS 403s erhält, die derselbe Code auf einer Heimverbindung problemlos durchläuft. Wohnadressen gehören zu Verbraucherinternetprovidern und werden als Personen behandelt; Mobilfunkanbieter-IPs sitzen hinter CGNAT mit Tausenden von echten Abonnenten, was sie am schwersten zu blockieren macht.
Also ist Sprosse 3 ein Austausch, kein Umschreiben: senden Sie dieselbe gut geformte Anfrage von einem Wohn-Exit. QuantumProxies betreibt über 90 Millionen Wohn-IPs in über 200 Ländern mit rotationsbasierten oder festen Sitzungen pro Anfrage, HTTP und SOCKS5 in jedem Plan und Abrechnung pro GB – eine Konfigurationszeile ändert das ASN, das Ihr Ziel sieht. Bereits auf Wohnadressen und immer noch blockiert? Überprüfen Sie den Ruf des Pools mit unserem kostenlosen IP-Qualitätsbewertungstool: alles über 75 ist verbrannt und wird 403s sammeln, egal wie gut Ihre Header sind.
Überspringen Sie die Leiter: holen Sie sich jede Seite mit der Scraper API

Sprosse 4: Rendering und Herausforderungen
Die letzte Sprosse ist die teure. Einige 403s sind die sichtbare Hälfte einer JavaScript-Herausforderung: Der Server liefert ein kleines Skript, erwartet eine Antwort innerhalb von Sekunden und verweigert alles, was es nicht ausführen kann. Kein Header-Set und keine IP beheben das, weil der Test ist, ob Sie Code ausführen können. Optionen in aufsteigenden Kosten: ein headless Browser mit einem Stealth-Patch-Set, ein verwalteter Browser-Pool oder eine Scraping-API, die bei Bedarf rendert. Rendering kostet pro Seite viele Male mehr als eine einfache HTTP-Anfrage, also eskalieren Sie nur für die URLs, die es wirklich benötigen.
Die QuantumProxies Scraper API fasst die Sprossen 2 bis 4 in eine Anfrage zusammen: Browser-grade TLS, Wohn-Exits, JavaScript-Rendering, wenn eine Seite es benötigt, und Markdown, JSON oder rohes HTML zurück. Das ist der ehrliche Handel – Sie hören auf, die Leiter zu pflegen, und zahlen stattdessen pro erfolgreicher Seite.
Die Leiter in der Praxis anwenden
- Testen Sie nach jeder einzelnen Änderung erneut. Zwei Änderungen auf einmal und Sie lernen nichts darüber, welche funktioniert hat.
- Cache den rohen 403-Körper während der Entwicklung. Blockseiten tragen Ray-IDs, Regel-Namen und Anbieter-Fingerprints, die Ihren Gegner benennen.
- Behandeln Sie einen 403 bei der allerersten Anfrage als Identitätsproblem; ein 403, das nach 200 guten Seiten erscheint, ist ein Ruf- oder Timing-Problem.
- Versuchen Sie einen 403 höchstens einmal erneut und nur nach einer Änderung. Das gleiche Anfrage von derselben IP zu hämmern, verwandelt eine weiche Blockierung in eine harte.
- Wenn eine öffentliche API oder ein Feed für dieselben Daten existiert, verwenden Sie sie. Es ist billiger als jede der oben genannten Sprossen und bricht nie bei einem Redesign.
Verhinderung von Sperren ist die Geschwisterdisziplin: Sobald Sie eine 200 haben, ist es eine Frage des Timings, der Sitzungs-Hygiene und der Pool-Gesundheit, sie zu behalten, anstatt sich zu tarnen.
Häufig gestellte Fragen
Was verursacht einen 403 Forbidden-Fehler im Web Scraping?
Erkennung, in fast jedem Fall. Die üblichen Auslöser sind ein Standardbibliothek-User-Agent, ein unvollständiges oder widersprüchliches Header-Set, eine Rechenzentrum-IP mit schlechtem Ruf, eine Anforderungsfrequenz, die zu regelmäßig ist, oder ein TLS-Fingerprint, der nicht zu dem Browser passt, den Sie zu sein behaupten. Echte Berechtigungsfehler existieren, aber sie geben auch 403 an Browser zurück – testen Sie in einem, bevor Sie etwas annehmen.
Wie umgehe ich einen 403 Forbidden-Fehler in Python?
Arbeiten Sie die Leiter ab. Fügen Sie einem requests.Session ein vollständiges Browser-Header-Set hinzu; wenn das fehlschlägt, wechseln Sie zu einem Client, der Browser-TLS imitiert, wie curl_cffi; wenn das fehlschlägt, leiten Sie durch einen Wohn-Proxy; wenn die Seite eine JavaScript-Herausforderung liefert, rendern Sie sie oder verwenden Sie eine Scraping-API. Eskalieren Sie nur, wenn die günstigere Sprosse tatsächlich getestet wurde.
Warum gibt httpx 403 zurück, wenn mein Browser es nicht tut?
Aus dem gleichen Grund wie requests: httpx sendet ein minimales Header-Set und einen Python-TLS-Fingerprint. Kopieren Sie die genaue Anfrage des Browsers aus den DevTools, spielen Sie sie mit httpx ab, und der 403 verschwindet normalerweise – was Ihnen sagt, dass der Unterschied die Header waren. Wenn es mit identischen Headern bestehen bleibt, liegt die Blockierung auf der TLS- oder IP-Ebene.
Wie behebe ich 403 Forbidden in Scrapy?
Setzen Sie einen realistischen DEFAULT_REQUEST_HEADERS plus USER_AGENT, halten Sie ROBOTSTXT_OBEY ehrlich darüber, was Sie abrufen dürfen, aktivieren Sie AUTOTHROTTLE_ENABLED und leiten Sie Anfragen durch eine rotierende Proxy-Middleware. Scrapy-Wiederholungen versuchen standardmäßig nicht, 403 zu wiederholen – fügen Sie es nur dann zu RETRY_HTTP_CODES hinzu, wenn Sie die IP zwischen den Versuchen wechseln.
Ein 403 ist Information, keine Wand. Es sagt Ihnen, welches der vier Signale Sie verraten hat, und jede Sprosse der Leiter kostet mehr als die darunter. Beginnen Sie bei der günstigsten, testen Sie nach jeder Änderung und hören Sie auf zu klettern, sobald der Statuscode 200 wird.