Proxy in Python requests konfigurieren: Authentifizierung und Fehler prüfen
Proxy in Python Requests setzen: HTTP und SOCKS5, Login in der URL, Session gegen Umgebung, Timeouts, TLS und die genaue Bedeutung von 407, ProxyError und SSLError.
Dieser Text ist für Leute, die Python Requests über einen Proxy schicken und den Weg prüfen wollen. Die Snippets nutzen Platzhalter und Dummy-Zugangsdaten.
01Proxy in requests einrichten und den Weg prüfen
Die Beispiele folgen der offiziellen Requests-Dokumentation zu Proxys und wurden am 14. Oktober 2026 gegen eine lokale Loopback-Fixture wiederholt: Python 3.14.6, Requests 2.34.2, urllib3 2.8.0, PySocks 1.7.1, TLS-Prüfung an. Das Labor zeigt Protokollverhalten, nicht Geschwindigkeit, Geografie oder die Qualität einer Anbieter-IP.
Jede Request-Methode nimmt ein Dict proxies. Die Schlüssel sind das Schema der Ziel-URL. Die Werte sind die Proxy-URL:
import requests
proxies = {
"http": "http://203.0.113.10:8080",
"https": "http://203.0.113.10:8080",
}
session = requests.Session()
session.trust_env = False
r = session.get("https://example.com/", proxies=proxies, timeout=(3.05, 27))
print(r.status_code)
- Legen Sie eine
Sessionan und setzen Sietrust_env = False, solange Sie den Proxy selbst wählen. - Tragen Sie HTTP und HTTPS auf denselben Proxy, wenn Ihr Anbieter einen HTTP-Proxy mit CONNECT anbietet.
- Setzen Sie immer ein Timeout-Tupel, sonst kann der Aufruf hängen.
- Schicken Sie eine kleine GET-Anfrage an einen Endpunkt, den Sie kontrollieren.
- Lesen Sie die Antwort und die Proxy-Logs. Ein Browser auf Meine IP ist der Browser-Ausgang, nicht der Python-Weg.
In der Fixture lieferte der direkte GET gegen den lokalen Origin HTTP 200. Derselbe GET über den offenen Loopback-Proxy ebenfalls 200. Der Proxy sah die absolute Form GET http://127.0.0.1:…/ HTTP/1.1. Ohne diesen Trace wissen Sie nur, dass irgendetwas 200 gesagt hat.
Requests akzeptiert in 2.34.2 auch 127.0.0.1:8080 ohne Schema. Der Aufruf kam in der Fixture mit HTTP 200 durch, intern wird http:// ergänzt. Schreiben Sie das Schema trotzdem. Ohne http:// oder socks5:// ist die URL mehrdeutig, sobald SOCKS im Spiel ist.
Ein Schlüssel der Form https://api.intern.example gilt nur für genau diesen Host, nicht für Unterdomänen.
02HTTP-Proxy und HTTPS-Ziel richtig unterscheiden
Der Eintrag "https" zeigt fast immer auf eine http://-Proxy-URL. Das ist Absicht. Requests schickt dem Proxy CONNECT host:443 und spricht TLS erst im Tunnel. In der Fixture stand in den Proxy-Ereignissen CONNECT localhost:50855 HTTP/1.1, während das Ziel https://localhost:…/ war. Das Schema der Ziel-URL ist nicht das Schema des Proxy-Endpunkts.

https:// in der Proxy-URL brauchen Sie nur, wenn der Anbieter TLS direkt auf dem Proxy-Port terminiert. Das ist ein anderer Dienst als ein klassischer Forward-Proxy.
HTTP zum Origin geht als Absolute-Form-GET. HTTPS geht als CONNECT. Dieselbe fehlende Anmeldung sieht deshalb anders aus:
| Symptom in Requests 2.34.2 | Schicht | Was prüfen |
|---|---|---|
| Antwortstatus 407, Body "Proxy Authentication Required" | HTTP-Proxy, Absolute-Form-GET | Benutzer, Passwort, Prozentkodierung. Keine Exception. |
ProxyError, Text enthält Tunnel connection failed: 407 | CONNECT zum HTTPS-Ziel | Dieselbe Anmeldung, aber am Tunnel. HTTPProxyAuth reicht hier nicht. |
| Antwortstatus 401 nach gültigem Proxy-Login | Zielserver | Proxy ist durch. Die App am Origin lehnt ab. |
ProxyError mit ConnectTimeoutError | TCP zum Proxy | Host, Port, Firewall. Das Timeout gilt für den Connect, nicht für die ganze Anfrage. |
ConnectionError mit innerem ReadTimeoutError nach Headern | Lesen vom Origin | Header waren da. Der Body kam zu langsam. |
SSLError / CERTIFICATE_VERIFY_FAILED | TLS zum Ziel im Tunnel | CA des Ziels oder des interceptierenden Proxys, nicht verify=False. |
ConnectionError, nodename nor servname provided bei socks5:// | DNS auf dem Client | Hostname unauflösbar. socks5h:// schickt den Namen an den Proxy. |
Wenn Sie nur wissen wollen, ob ein Endpunkt überhaupt antwortet, reicht der Proxy-Checker. Für die längere Checkliste siehe So prüfen Sie, ob ein Proxy funktioniert. Beides ersetzt kein Python-Trace.
03Benutzername und Passwort sicher übergeben
Die Dokumentation verlangt Basic Auth in der Proxy-URL, mit Prozentkodierung pro Komponente. Sonderzeichen im Passwort gehören nicht roh in die URL. RFC 7617 Abschnitt 2 macht den user-id nach dem Decodieren ungültig, sobald er einen Doppelpunkt enthält. Der erste Doppelpunkt trennt Benutzer und Passwort. Prozentkodierung eines Doppelpunkts im Benutzernamen ändert daran nichts. Das Passwort darf Doppelpunkte enthalten, unser Dummy tut das.
from urllib.parse import quote
user = quote("demo", safe="")
password = quote("p@ss:/#%", safe="")
proxies = {
"http": f"http://{user}:{password}@203.0.113.10:8080",
"https": f"http://{user}:{password}@203.0.113.10:8080",
}
Ohne Anmeldung lieferte der lokale Auth-Proxy auf HTTP den Status 407 als normale Antwort. Derselbe fehlende Header auf HTTPS wurde zu requests.exceptions.ProxyError mit OSError('Tunnel connection failed: 407 Proxy Authentication Required'). Nicht jeder 407 sieht gleich aus. Eine Diagnose-Seite zu Status 407 im Browser ist ein anderes Thema als dieser CONNECT-Fall.
Falsche Dummy-Zugangsdaten in der URL, Benutzer demo, Passwort nicht das erwartete, lieferten auf HTTP den Status 407. Der Proxy sah Proxy-Authorization und lehnte ab. Derselbe falsche Login auf HTTPS wurde zu ProxyError mit 407 am CONNECT. Mit den richtigen kodierten Dummy-Daten kamen HTTP und HTTPS-CONNECT auf 200, sobald die Labor-CA für das selbst signierte Ziel gesetzt war.
HTTPProxyAuth ist die Falle, die in Foren immer wieder auftaucht:
from requests.auth import HTTPProxyAuth
auth = HTTPProxyAuth("demo", "p@ss:/#%")
session.get(url, proxies=bare_proxies, auth=auth, timeout=(3.05, 10))
In der Fixture: HTTP-GET mit HTTPProxyAuth war 200. Derselbe auth= auf https://localhost endete wieder in ProxyError mit 407 am CONNECT. urllib3 setzt den Header aus HTTPProxyAuth nicht zuverlässig auf den Tunnel. Die Zugangsdaten gehören in die Proxy-URL.

Loggen Sie die URL nicht. In unseren Rohdaten ist das Passwort durch *** ersetzt. Ein 401 vom Origin bei gültigem Proxy-Login blieb 401. Das ist die App, nicht der Proxy.
04Session, Umgebungsvariablen und trustenv verstehen
Eine Session hält Verbindungspool und Defaults. Die Docs warnen ausdrücklich: Werte in session.proxies können von Umgebungsproxys überschrieben werden, die urllib.request.getproxies() liefert. Issue psf/requests#2018 beschreibt denselben Effekt.
In der Fixture zeigte Session.proxies auf den offenen Loopback-Proxy, während HTTP_PROXY und HTTPS_PROXY auf einen zweiten zeigten. Der GET ohne proxies= am Aufruf landete beim Umgebungsproxy. Dieselbe Session mit proxies= am Aufruf traf den offenen Proxy. Eine zweite Session mit trust_env = False ignorierte die Umgebung und nutzte Session.proxies.

Zwei belastbare Muster:
# 1. proxies an jedem Aufruf, wie in den Docs empfohlen
session.get(url, proxies=proxies, timeout=10)
# 2. Umgebung für diese Session abschalten
session.trust_env = False
session.proxies.update(proxies)
trust_env = False liest auch kein .netrc und keine CA-Variablen wie REQUESTS_CA_BUNDLE. Wenn Ihr Unternehmen die CA genau darüber setzt, müssen Sie verify= selbst übergeben.
Ohne proxies= liest Requests http_proxy, https_proxy, no_proxy und all_proxy. In einem normalen Prozess, ohne REQUEST_METHOD, reichte in der Fixture allein HTTP_PROXY/HTTPS_PROXY in Großbuchstaben. Der GET landete beim Umgebungsproxy. CPython urllib.request.getproxies_environment verwirft Großschreibung von HTTP_PROXY für das Schema http, sobald REQUEST_METHOD gesetzt ist, CGI-Schutz gegen einen Proxy:-Header. Dieselbe Fixture mit REQUEST_METHOD=GET und nur Großschreibung ging direkt, der Umgebungsproxy sah nichts. Kleingeschriebenes http_proxy galt auch mit REQUEST_METHOD. curl behandelt HTTP-Proxy-Variablen historisch anders, oft nur kleingeschrieben. Die beiden Welten nicht mischen.
NO_PROXY=127.0.0.1,localhost übersprang den Umgebungsproxy, der GET ging direkt. Dieselbe Session mit explizitem proxies= schickte denselben Host trotzdem durch den Proxy. NO_PROXY gilt für den Weg aus der Umgebung, nicht für ein Dict, das Sie übergeben.
Zugangsdaten in der Shell-Umgebung oder in Git sind ein Risiko. Die Docs sagen das klar. Für Skripte gehören Secrets in den Secret-Store der CI, nicht in export HTTPS_PROXY=http://user:pass@….
05SOCKS5, socks5h und DNS prüfen
SOCKS ist optional. Die Docs verlangen python -m pip install 'requests[socks]'. In der Fixture hing PySocks 1.7.1. Ohne Extra gibt es keinen stillen Fallback auf HTTP.
proxies = {
"http": "socks5://demo:***@203.0.113.10:1080",
"https": "socks5://demo:***@203.0.113.10:1080",
}
socks5 löst DNS auf dem Client. socks5h schickt den Hostnamen an den Proxy, analog zu curl. Das steht in den Requests-Docs zu SOCKS. Ein erfolgreicher Request beweist die Auflösung nicht.
Gegen http://127.0.0.1:…/ sah der SOCKS-Server ATYP IPv4, Ziel 127.0.0.1. Gegen http://lab-origin.invalid:…/ mit socks5:// kam ConnectionError / NewConnectionError, errno 8, nodename nor servname provided, or not known. Der Proxy bekam diese Anfrage nicht. Mit socks5h:// kam HTTP 200, der Server notierte ATYP Hostname und lab-origin.invalid. HTTPS nach localhost über socks5h mit Labor-CA war ebenfalls 200, Ziel als Hostname.

Wenn Ihr Anbieter den Namen intern auflösen soll, weil die Exit-Maschine andere Resolver hat als Ihr Laptop, ist socks5h die Variante. socks5 ist richtig, wenn der Client den Namen kennen muss. Der Unterschied HTTP gegen SOCKS5 in der Produktwahl steht in SOCKS5 vs HTTP-Proxys. Protokoll ist nicht IP-Herkunft. Ein Datacenter-HTTP-Proxy und ein Residential-SOCKS5 können denselben Requests-Code füttern und trotzdem völlig verschiedene Exit-Netze haben.
06Timeouts, TLS und Verbindungsfehler eingrenzen
Timeouts in Requests sind kein Gesamtdeadline. Ein Float oder das erste Element des Tupels begrenzt den Connect. Das zweite Element begrenzt die Pause zwischen Bytes beim Lesen. Ohne Timeout wartet Requests unbegrenzt.
Gegen einen lokalen Listener, dessen Accept-Warteschlange voll war, mit timeout=(0.8, 5) kam nicht ConnectTimeout oben. Es kam requests.exceptions.ProxyError, Kette MaxRetryError → urllib3.exceptions.ProxyError → ConnectTimeoutError → TimeoutError. Die Phrase Max retries exceeded beweist keine wiederholten Connects. Der installierte HTTPAdapter hat max_retries.total = 0. urllib3 verpackt den ersten Fehlversuch trotzdem in MaxRetryError.
Ein konfiguriertes urllib3.util.Retry haben wir nicht gemessen. Wenn Sie es setzen, zählt total zusätzliche Versuche, keine Wanduhr. allowed_methods steuert Status- und Read-Retries. POST fehlt dort standardmäßig, Connect-Fehler an POST werden davon nicht ausgeschlossen. Für Status-Retries mit gesetzter Liste kann Retry-After die Pause strecken. Das ist Doku und Default-Objekte, kein Lauf in dieser Fixture.
Ein Origin, der Header sofort schickte und den Body vier Sekunden liegen ließ, mit timeout=(3.05, 1.0), endete als ConnectionError mit innerem ReadTimeoutError und dem Text Read timed out. Nicht als top-level ReadTimeout. Der offene Proxy hatte das GET schon angenommen. Endloses Retry gegen denselben toten Host ändert daran nichts. Rotieren, bis irgendein Exit den Zielstatus 403 umgeht, nein.
TLS bleibt an. SSL-Prüfung ist Standard. Das selbst signierte Laborziel mit verify=True war SSLError / SSLCertVerificationError: self-signed certificate. Mit verify= auf die Labor-CA kam HTTP 200 durch denselben CONNECT. verify=False war kein Fall und ist kein normaler Fix. Wenn ein Anbieter TLS bricht, brauchen Sie dessen CA in verify= oder in einem expliziten Bundle, nicht das Abschalten der Prüfung.
trust_env = False nimmt Ihnen REQUESTS_CA_BUNDLE. Setzen Sie die Datei dann am Aufruf. Interceptierende Firmenproxys sind genau dieser Fall.
07Passenden Endpoint auswählen und Ergebnisse prüfen
Ein lokaler 200er beweist nicht, dass ein Anbieter in Frankfurt, mit Mobile-Exit oder mit Account-Login funktioniert. Er beweist, dass Ihr Client CONNECT, Auth und TLS so spricht, wie Requests 2.34.2 es erwartet.
Für den Alltag:
- Nehmen Sie den Endpunkt, den der Anbieter für HTTP-Clients dokumentiert, inklusive Schema und Port.
- Kodieren Sie Benutzer und Passwort, legen Sie sie in die Proxy-URL, nicht in
HTTPProxyAuth, sobald HTTPS-Ziele vorkommen. - Schalten Sie die Umgebung mit
trust_env = Falseoder übergeben Sieproxies=an jedem Aufruf. - Setzen Sie
(connect, read)so knapp, dass ein toter Proxy Sie nicht blockiert. - Vergleichen Sie den Origin, den Ihr Python-Request sieht, mit der Range, die der Anbieter für den Plan nennt. Meine IP im Browser ist ein zweiter Ausgang.
Residential- und Mobile-Exits unterscheiden sich in der Herkunft, nicht im proxies-Dict. Die Katalogseiten Residential-Proxys und Mobile Proxys filtern den Typ. Requests bleibt dieselbe Bibliothek. Wenn der Dienst hängt, grenzt Proxy funktioniert nicht die Schicht ein, bevor Sie den Client umschreiben.

SOAX verkauft rotierende Residential- und Mobile-Proxys über einen gemeinsamen Credit-Pool, mit Datacenter und ISP in denselben Plänen. Der Builder startet bei $200/mo + VAT (200 Credits); Tier-1-Traffic kostet $3/GB im Builder.

Bright Data ist ein großes Proxy-Netz für Datenerhebung: Residential-, Mobile-, ISP- und Datacenter-IPs in rund 195 Ländern. Residential-Traffic lässt sich ohne Abo nach Verbrauch bezahlen, Datacenter- und ISP-Adressen gibt es in Paketen ab 10 IPs. Für Residential und Mobile ist eine Identitätsprüfung nötig.

Oxylabs verkauft Residential-, Mobile-, ISP- und Datacenter-Proxys in einem einzigen Monatsabo ab 30 $. Zahlung: Karte, Überweisung, AliPay, PayPal.

Decodo (ehemals Smartproxy) verkauft Residential- und Datacenter-Proxys. Residential: $4/GB ohne Monatsplan oder monatliche Pakete ab $3.75/GB für 3 GB. Zahlungen: Karten, PayPal, Alipay, Google/Apple Pay, Krypto (mit Einschränkungen).
Das ist keine Protokoll- oder Auth-Prüfung dieser Anbieter. Die Fixture hat sie nicht gerufen. Für Requests brauchen Sie einen HTTP-Forward-Proxy mit CONNECT für HTTPS-Ziele oder SOCKS5/SOCKS5h, Login in der URL, Benutzer ohne Doppelpunkt nach RFC 7617, Passwort komponentenweise kodiert. Ob ein Dienst das so anbietet, steht in dessen aktueller Doku.
Warum steht unter https oft eine http-Proxy-URL?
Reicht HTTPProxyAuth für HTTPS-Seiten?
Warum überschreibt die Umgebung meine Session.proxies?
Was bewirkt NO_PROXY, wenn ich proxies= setze?
Wann socks5, wann socks5h?
Ist ProxyError immer ein 407?
Darf ich verify=False setzen, bis der Proxy läuft?
Ähnliche Artikel
Wie mobile Proxys funktionieren: IP-Rotation und Sitzungen
Warum eine Website Sie nach dem IP-Wechsel noch kennt: woraus ein mobiler Ausgang besteht, wozu Netzbetreiber CGN nutzen, drei Arten von „Sitzung“, was Rotation wirklich ändert und was Sie vor der Miete prüfen.
Kostenlose Proxys: Risiken, Grenzen und ein sicherer Test
Sind kostenlose Proxys sicher? Was der Betreiber mitlesen kann, warum HTTPS nicht alles schützt, wo Gratis-Listen scheitern und wie Sie einen Test richtig deuten.
ISP- vs. Residential-Proxys: feste IP oder wechselnder Pool?
Was ein ISP-Proxy ist, warum eine statische IP etwas anderes als eine Sticky-Session ist, wie sich Preise pro IP und pro GB vergleichen lassen und was für lange Sitzungen passt.



