Ein häufiges Muster in Support-Gesprächen: Jemand wechselt zu Residential Proxies, die Blockrate verbessert sich, und trotzdem verweigert eine hartnäckige Untergruppe von Zielen den Zugriff weiterhin. Die IP ist sauber, die Geografie stimmt, und die Anfragen werden trotzdem herausgefordert. Fast immer liegt die Antwort in den Headern, denn die Adresse bringt einen bis zur Tür, aber die Header entscheiden, ob das, was hindurchgeht, wie ein Browser aussieht.
Der Fehler, der den meisten Header-Problemen zugrunde liegt, ist, sie als eine Liste von Werten zu betrachten, die korrekt gesetzt werden müssen. Das ist es nicht. Es ist eine Menge von Behauptungen, die miteinander und mit allem anderen an Ihrer Verbindung übereinstimmen müssen, und eine Anfrage, die aus nicht zusammenpassenden Teilen zusammengesetzt ist, ist verdächtiger als eine ohne jeden Aufwand.
Konsistenz schlägt jeden Einzelwert
Beginnen Sie hier, denn das rahmt alles Folgende neu ein. Ein Server bewertet Ihren User-Agent nicht isoliert. Er sieht ein Bündel: den UA-String, die begleitenden Client Hints, den Header-Satz und seine Reihenfolge, den Accept-Language-Wert, den TLS-Handshake darunter und die IP, von der das Ganze kam. Echte Browser erzeugen intern konsistente Bündel, weil dieselbe Software alles davon generiert hat.
Scraper erzeugen unbeabsichtigt inkonsistente Bündel. Ein Chrome-UA, der mit dem Header-Satz einer Python-HTTP-Bibliothek ankommt, ein Windows-UA über einem TLS-Fingerabdruck, der zu einem Linux-Tool gehört, ein US-Exit, der Accept-Language: de-DE sendet, oder ein behaupteter Browser, der nie die Assets anfordert, die ein Browser anfordern würde. Keines davon sagt für sich genommen “Bot”, aber der Widerspruch tut es, und Widersprüche sind viel einfacher zuverlässig zu erkennen als jedes einzelne Signal. Das ist dieselbe Logik wie bei der Geräte-und-Netzwerk-Paarung in Antidetect-Browsern: Jede Schicht muss dieselbe Geschichte erzählen.
Das Ziel ist also nicht der überzeugendste UA-String. Es ist eine Anfrage, bei der UA, Header, TLS-Fingerabdruck und Exit-Adresse alle denselben plausiblen Besucher beschreiben.
Was ein echter Browser tatsächlich sendet
Wenn Sie nur User-Agent setzen, sind Sie bereits inkonsistent, denn kein Browser sendet einen UA und sonst nichts. Eine moderne Chrome-Anfrage für eine Seite trägt mindestens einen Satz entlang dieser Linien:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.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-US,en;q=0.9
Accept-Encoding: gzip, deflate, br, zstd
sec-ch-ua: "Chromium";v="141", "Not?A_Brand";v="24", "Google Chrome";v="141"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
Drei Dinge darin sind es wert, verstanden statt kopiert zu werden.
Client Hints müssen zum UA passen. Die sec-ch-ua-Markenliste, sec-ch-ua-platform und sec-ch-ua-mobile sind eine strukturierte Wiederholung dessen, was der UA-String bereits behauptet. Wenn Ihr UA Chrome auf Windows angibt und Ihr Platform-Hint macOS angibt, oder die Version in der Markenliste von der Version im UA abweicht, haben Sie sich in zwei benachbarten Headern widersprochen. Gar keine Client Hints zu senden, während man behauptet, ein aktuelles Chrome zu sein, ist ebenfalls eine Nichtübereinstimmung, da ein echtes Chrome sie sendet.
Sec-Fetch-Header beschreiben den Kontext. Sie sagen dem Server, um welche Art von Anfrage es sich handelt: eine Top-Level-Navigation, ein Subresource-Fetch, ein Same-Origin-XHR. Ein Seitenaufruf ist Dest: document, Mode: navigate, Site: none bei direktem Öffnen oder same-origin, wenn ein interner Link gefolgt wird. Ein XHR an eine API ist Dest: empty, Mode: cors. Diese falsch zu setzen ist ein Verräter, gerade weil sie in einem Browser automatisch sind und in einem Skript leicht vergessen werden.
Accept-Encoding ist eine Behauptung, die Sie einhalten müssen. Werben Sie nur dann mit br und zstd, wenn Ihr Client sie tatsächlich dekomprimieren kann. Manche Bibliotheken werben mit Kodierungen, die sie dann nicht verarbeiten können, was entweder zu Fehlern oder zu einem Fallback führt, der sich von dem unterscheidet, was ein Browser aushandeln würde.
Accept-Language auf das Exit-Land abstimmen
Dieser Punkt ist spezifisch für die Proxy-Arbeit und die häufigste selbstverschuldete Nichtübereinstimmung. Wenn Sie über eine deutsche Residential-IP gehen und Accept-Language: en-US senden, haben Sie einen Besucher beschrieben, dessen Browser für amerikanisches Englisch konfiguriert ist und auf einer deutschen Heimverbindung sitzt. Das kommt im echten Leben vor, ist aber ungewöhnlich genug, um ein Signal zu sein, und praktischer gesehen kann es ändern, was Sie zurückbekommen: Viele Seiten liefern Inhalte basierend auf diesem Header aus, sodass ein geo-gezielter Sammelvorgang die falsche Sprache abrufen kann, während er scheinbar funktioniert.
Binden Sie die Sprache an den Exit, idealerweise an derselben Stelle, an der Sie das Land auswählen, damit die beiden nie auseinanderdriften können:
import requests
MARKETS = {
"us": "en-US,en;q=0.9",
"de": "de-DE,de;q=0.9,en;q=0.8",
"fr": "fr-FR,fr;q=0.9,en;q=0.8",
"br": "pt-BR,pt;q=0.9,en;q=0.8",
}
UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36")
def fetch(url, country):
proxy = f"http://customer-USERNAME-country-{country}:PASSWORD@p.shifter.io:443"
headers = {
"User-Agent": UA,
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
"image/avif,image/webp,*/*;q=0.8",
"Accept-Language": MARKETS[country], # folgt dem Exit, immer
"Accept-Encoding": "gzip, deflate, br",
"sec-ch-ua": '"Chromium";v="141", "Not?A_Brand";v="24", '
'"Google Chrome";v="141"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"', # stimmt mit dem UA überein
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Upgrade-Insecure-Requests": "1",
}
return requests.get(url, headers=headers,
proxies={"http": proxy, "https": proxy}, timeout=20)
Dieselbe Disziplin gilt für Zeitzone und Gebietsschema, wenn Sie einen Browser steuern, wo diese separat beobachtbar sind und ebenfalls zum Exit passen sollten, was enger wird, wenn Sie mit City-Level-Targeting arbeiten.
Den User-Agent nicht zufällig rotieren
Das ist ein Ratschlag, der weit verbreitet ist und mehr schadet als nützt. Einen zufälligen UA pro Anfrage zu wählen, erzeugt ein Muster, das keine echte Population aufweist: eine IP, die Chrome auf Windows ist, dann Safari auf einem Mac, dann Firefox auf Linux, innerhalb einer Minute. Schlimmer noch: Wenn Sie eine Sticky Session halten, sodass eine Adresse einen mehrstufigen Ablauf bedient, bedeutet das Ändern des UA mitten im Ablauf, dass derselbe Besucher scheinbar zwischen dem Klicken auf die Suche und dem Betrachten eines Ergebnisses das Gerät gewechselt hat.
Das kohärente Modell ist eine Identität pro Sitzung. Wählen Sie einen plausiblen UA, behalten Sie ihn für die Lebensdauer dieser Sitzung bei und halten Sie alles andere damit konsistent. Wenn Sie Vielfalt über Ihre Flotte hinweg möchten, variieren Sie zwischen Sitzungen statt zwischen Anfragen, und variieren Sie in realistischen Proportionen statt gleichmäßig über jeden Browser, der je existiert hat. Halten Sie auch die Versionen aktuell: Ein UA, der eine Browserversion von vor drei Jahren behauptet, ist selbst anomal, da echte Installationen sich aktualisieren.
Header sind nur eine Schicht
Es lohnt sich, hier ehrlich über die Obergrenze zu sein. Perfekte Header lassen einen Python-Client nicht wie Chrome aussehen, denn die Schicht darunter unterscheidet sich weiterhin. Der TLS-Handshake und die HTTP/2-Einstellungen, die Ihr Client erzeugt, bilden einen eigenen Fingerabdruck, und ein Chrome-UA über einem Fingerabdruck, der Python signalisiert, ist genau der Widerspruch, der zu Beginn besprochen wurde. Diese Nichtübereinstimmung ist Gegenstand von TLS- und HTTP/2-Fingerprinting, und deshalb bleiben manche stark verteidigte Ziele für einfache HTTP-Clients unerreichbar, unabhängig von der Header-Arbeit, was einer der Gründe ist, zu einem Headless-Browser zu greifen.
Die Header-Reihenfolge ist aus demselben Grund wichtig. Browser geben Header in einer stabilen Reihenfolge aus; viele HTTP-Bibliotheken geben sie alphabetisch oder in Einfügereihenfolge aus, was eine weitere Möglichkeit ist, wie das Bündel seinen Ursprung verraten kann, selbst wenn jeder Wert korrekt ist. Manche Clients erlauben es, die Reihenfolge zu kontrollieren, und wo es darauf ankommt, lohnt es sich, die Reihenfolge eines echten Browsers nachzubilden. Der breitere Katalog dieser Signale findet sich in den Fingerprints, die die Datenextraktion blockieren können, und die häufigen selbstverschuldeten Varianten in Fehlern, die Erkennung auslösen.
Eine kurze Checkliste
Senden Sie einen vollständigen Browser-Header-Satz, nicht nur einen User-Agent. Sorgen Sie dafür, dass Client Hints mit dem UA bei Marke, Version, Plattform und Mobile-Flag übereinstimmen. Setzen Sie Sec-Fetch-Header so, dass sie den tatsächlichen Anfragetyp beschreiben. Binden Sie Accept-Language an das Exit-Land und halten Sie beide im selben Code-Pfad. Werben Sie nur mit Kodierungen, die Sie dekodieren können. Halten Sie eine Identität pro Sitzung statt pro Anfrage zu rotieren, und halten Sie UA-Versionen aktuell. Prüfen Sie dann, ob Ihr TLS-Fingerabdruck mit dem Browser übereinstimmt, den Sie vorgeben zu sein, denn das ist die Schicht, die Header nicht reparieren können.
Wenn ein Ziel Sie nach all dem immer noch abweist, hat sich das Problem verlagert: Pacing, IP-Reputation oder Verhaltenssignale, die zum breiteren Themenkomplex gehören, der in Blockaden vermeiden und stark geschützte Seiten scrapen behandelt wird.
Fazit
Header sind die zweite Hälfte der Identität, die Ihr Proxy in Gang setzt. Eine saubere Residential-Adresse macht die Verbindung unauffällig; ein kohärentes Header-Bündel macht die Anfrage unauffällig, und Kohärenz ist das ganze Spiel. Jede Behauptung muss mit jeder anderen Behauptung übereinstimmen: Client Hints mit dem UA, Sprache mit dem Exit-Land, Fetch-Metadaten mit dem Anfragetyp, Kodierungen mit Ihren tatsächlichen Fähigkeiten, und der ganze Satz mit dem darunterliegenden TLS-Fingerabdruck. Eine Identität pro Sitzung, stabil gehalten, schlägt clevere Rotation jedes Mal.
Diese Verbindungsschicht ist das, was Residential Proxies bieten: echte Heim-Adressen mit Land- und Stadt-Targeting, sodass die Geografie, die Ihre Header behaupten, die Geografie ist, aus der Sie tatsächlich austreten, abgerechnet pro GB, sodass die Feinabstimmung von Anfragen auf weniger Abruf Sie weniger kostet.