Beheben von ProxyError, SSLError & ConnectTimeout in Requests
requests.exceptions.ProxyError ist ein Symptom, keine Ursache. Hier wird die Ausnahmehierarchie entschlüsselt, jeder Traceback seiner tatsächlichen Lösung zugeordnet und eine Gesundheitsprüfungsfunktion bereitgestellt, die Fehler klassifiziert und um tote Exits rotiert.
requests.exceptions.ProxyError ist eine der am wenigsten hilfreichen Fehlermeldungen in Python: Sie wird bei einem toten Proxy, falschen Anmeldedaten, einem schlechten Schema, einem überlasteten Exit und einer Firewall-Blockade ausgelöst, alle mit nahezu identischen Tracebacks. Der Trick, es schnell zu beheben, besteht darin zu wissen, dass ProxyError keine Grundursache ist — es ist eine Kategorie. Im Requests-Quellcode sind ProxyError, SSLError und ConnectTimeout alle Unterklassen von ConnectionError, und jede wird in einer bestimmten Phase des Anforderungslebenszyklus ausgelöst. Lesen Sie die Phase und Sie erkennen die Ursache. Dieser Leitfaden entschlüsselt die Ausnahmehierarchie, ordnet jedem häufigen Traceback seine tatsächliche Lösung zu und bietet Ihnen eine Gesundheitsprüfungsfunktion, die Fehler klassifiziert und automatisch um sterbende Exits rotiert.
Die Ausnahmehierarchie von Requests
Jeder proxybezogene Fehler in Requests leitet sich von RequestException ab. Der nützliche Zweig zum Debuggen ist ConnectionError, da die drei Ausnahmen, die Sie tatsächlich treffen, alle darunter liegen:
- ProxyError — wird ausgelöst, wenn die Verbindung zum Proxy selbst fehlschlägt: unerreichbarer Host, falscher Port, abgelehnte Verbindung oder ein abgelehnter
407. Die Nachricht nistet oftCannot connect to proxyin einemHTTPSConnectionPool(...)-Wrapper. - SSLError — der Proxy hat sich verbunden, aber der TLS-Handshake zum Ziel ist fehlgeschlagen. In Proxy-Setups ist der übliche Auslöser
https://, das imhttps-Schlüssel anstelle vonhttp://geschrieben ist. - ConnectTimeout — der Proxy hat nicht innerhalb des Verbindungsfensters geantwortet. Es ist sowohl eine Unterklasse von
ConnectionErrorals auch vonTimeoutund wird ausdrücklich als sicher zum Wiederholen dokumentiert. - ReadTimeout — der Proxy hat sich verbunden und die Anfrage weitergeleitet, aber das Ziel war zu langsam, um zu antworten. Dies ist ein Ziel- oder Exit-Qualitätsproblem, kein Konfigurationsfehler.
- MissingSchema / InvalidProxyURL — wird vor jedem Netzwerkaufruf ausgelöst, wenn die Proxy-URL fehlerhaft ist. Dies sind reine Tippfehler.
Da die ersten drei einen gemeinsamen Elternteil haben, fängt ein except requests.exceptions.ConnectionError alle für die Wiederholungslogik ab — während das individuelle Abfangen der Unterklassen Ihnen ermöglicht, zu protokollieren, warum jeder fehlgeschlagen ist. Die saubere Einrichtung, die die meisten dieser Fehler vermeidet, wird in unserem Python Requests Proxy-Leitfaden behandelt; dieser Beitrag handelt davon, was zu tun ist, wenn der Traceback bereits auf dem Bildschirm ist.
Eine Gewohnheit spart mehr Zeit als jede einzelne Lösung: Lesen Sie den Traceback von unten nach oben. Requests umschließt den zugrunde liegenden urllib3-Fehler, sodass die oberen Frames beschreiben, wo der Aufruf gemacht wurde, und die unteren Frames beschreiben, was schiefgelaufen ist. Die Zeile, die Sie wollen, ist die innerste Caused by-Klausel — sie benennt das konkrete Versagen (eine abgelehnte Verbindung, ein Zertifikatsfehler, ein Parser-Fehler), das der äußere ProxyError oder ConnectionError nur erneut auslöst. Sobald Sie diese Zeile lesen können, ist der Rest dieses Leitfadens eine Nachschlagetabelle.
Der klassische ValueError vor ProxyError
Der am häufigsten gesuchte Proxy-Traceback ist nicht einmal ein ProxyError — es ist ValueError: invalid literal for int() with base 10, tief in urllib3 ausgelöst. Es passiert, wenn Sie Anmeldedaten ohne Schema in den Proxy-Wert einbetten, sodass der Parser den Text nach dem Doppelpunkt als Portnummer liest:
# Broken — no scheme, so 'pass@host' is parsed as host:port
proxies = {"https": "user:pass@45.11.22.33:8000"}
# -> ValueError: invalid literal for int() with base 10: 'pass@45.11.22.33'
# Fixed — scheme in front, password URL-encoded if it has @ : or /
from urllib.parse import quote
pw = quote("p@ss:word", safe="")
proxies = {
"http": f"http://user:{pw}@gate.quantumproxies.io:PORT",
"https": f"http://user:{pw}@gate.quantumproxies.io:PORT",
}

Eine Proxy-Gesundheitsprüfung, die Fehler klassifiziert
Anstatt zu raten, fangen Sie jeden Ausnahmetyp ab und verwandeln ihn in ein einfaches englisches Urteil. Diese Funktion gibt die Exit-IP bei Erfolg und einen beschrifteten Grund bei Misserfolg zurück — setzen Sie sie vor jeden Scrape, um zu bestätigen, dass der Proxy lebt, bevor Sie Anfragen darauf verschwenden. Sie funktioniert gegen jedes authentifizierte Gateway, einschließlich residential proxies:
import requests
def check_proxy(proxies, url="https://httpbin.org/ip", timeout=(5, 20)):
try:
r = requests.get(url, proxies=proxies, timeout=timeout)
r.raise_for_status()
return True, r.json().get("origin")
except requests.exceptions.ProxyError as e:
return False, f"proxy unreachable or auth rejected: {e}"
except requests.exceptions.SSLError as e:
return False, f"TLS failed (https:// in the https key?): {e}"
except requests.exceptions.ConnectTimeout:
return False, "proxy did not answer within the connect window"
except requests.exceptions.ReadTimeout:
return False, "target too slow after connect (exit quality)"
except requests.exceptions.RequestException as e:
return False, f"other request error: {e}"
ok, detail = check_proxy(proxies)
print("OK" if ok else "FAIL", detail)
Wenn curl funktioniert, aber Python ProxyError auslöst
Wenn dieselben Anmeldedaten in curl erfolgreich sind, aber in Python ProxyError auslösen, überschreibt fast immer eine Umgebungsvariable Ihr Diktat. Requests liest HTTP_PROXY, HTTPS_PROXY und NO_PROXY aus der Shell, und ein veralteter Unternehmenswert leitet jeden Aufruf stillschweigend um. Drucken Sie session.proxies, um zu sehen, was wirklich verwendet wird, und deaktivieren Sie dann die Umgebungsabfrage vollständig:
import requests
session = requests.Session()
session.trust_env = False # ignore HTTP_PROXY / HTTPS_PROXY from the shell
session.proxies = {
"http": "http://USER:PASS@gate.quantumproxies.io:PORT",
"https": "http://USER:PASS@gate.quantumproxies.io:PORT",
}
print(session.get("https://httpbin.org/ip", timeout=(5, 20)).json())
Ein 407, der trotz korrekter Anmeldedaten bestehen bleibt, weist auf einen IP-Whitelist-Plan hin, der von einer nicht registrierten Adresse aufgerufen wird — die vollständige Liste der Ursachen finden Sie in unserem 407 Proxy Authentication Required-Leitfaden.
Intermittierender ProxyError: rotieren, nicht neu starten
Der frustrierende Fall ist Code, der zwanzig Minuten läuft, dann ProxyError auslöst und dann wieder funktioniert. Das ist kein Fehler in Ihrem Skript — es ist eine einzelne Exit-IP, die während des Laufs stirbt oder rate-limitiert wird. Die Lösung ist Wiederholen-mit-Rotation: Wickeln Sie den Aufruf ein, fangen Sie ConnectionError ab, und lassen Sie ein rotierendes Gateway Ihnen bei jedem neuen Versuch eine frische IP geben. Durch rotierende Proxies reist jeder Wiederholungsversuch über einen anderen Exit, sodass eine tote Adresse niemals eine Anfrage zweimal fehlschlagen lassen kann:
import requests
def get_with_rotation(url, proxies, attempts=4):
last = None
for _ in range(attempts):
try:
r = requests.get(url, proxies=proxies, timeout=(5, 20))
if r.status_code not in (429, 500, 502, 503, 504):
return r
last = r.status_code
except requests.exceptions.ConnectionError as e: # Proxy/SSL/ConnectTimeout
last = e
raise RuntimeError(f"failed after {attempts} attempts: {last}")
Wenn ProxyError über viele frische IPs hinweg bestehen bleibt, hat sich das Problem von Ihrem Pool zum Ziel verlagert: Sie werden blockiert, nicht getrennt. Das ist ein anderer Kampf — siehe die Anti-Ban-Checkliste für Taktung, Header und Sitzungs-Hygiene.
Es gibt noch eine weitere Unterscheidung, die es wert ist, verinnerlicht zu werden, da sie ändert, wie Sie reagieren. Ein ProxyError oder ConnectTimeout bedeutet, dass die Anfrage nie abgeschlossen wurde, sodass das Wiederholen selbst für einen POST sicher ist — auf der anderen Seite ist nichts passiert. Ein ReadTimeout hingegen bedeutet, dass das Ziel Ihre Anfrage erhalten hat und einfach zu lange gebraucht hat, um zu antworten; das Wiederholen eines nicht-idempotenten Schreibvorgangs kann eine doppelte Übermittlung verursachen. Wenn Sie die Wiederholungsschleife erstellen, behandeln Sie Verbindungsphasenfehler als frei wiederholbar und Lesephasenfehler als nur für GET und HEAD wiederholbar. Diese einzelne Regel verhindert den subtilen Fehler, bei dem ein instabiler Proxy einen Checkout in drei verwandelt.

Häufig gestellte Fragen
Was verursacht requests.exceptions.ProxyError: kann keine Verbindung zum Proxy herstellen?
Der Proxy-Host oder -Port ist falsch, der Proxy ist ausgefallen oder eine Firewall blockiert die Verbindung, bevor eine Anfrage gesendet wird. Überprüfen Sie den Endpunkt mit curl -x unter Verwendung derselben Anmeldedaten; wenn curl ebenfalls fehlschlägt, ist der Proxy unerreichbar, und wenn curl erfolgreich ist, ist eine Umgebungsvariable oder ein fehlerhaftes Diktat in Ihrem Python der Schuldige.
Warum ist ProxyError in HTTPSConnectionPool eingebettet?
Dieser Wrapper benennt einfach den Verbindungspool, den urllib3 verwendet hat, um das Ziel zu erreichen — es ist Rauschen um die eigentliche Nachricht, die darin verschachtelt ist. Lesen Sie die innerste Caused by-Klausel: Cannot connect to proxy bedeutet einen Verbindungsfehler, während eine 407- oder SSL-Nachricht im selben Pool auf ein Authentifizierungs- oder ein TLS/Schemaproblem hinweist.
Wie verhindere ich, dass Requests Proxies aus der Umgebung liest?
Setzen Sie session.trust_env = False in Ihrer Session, oder übergeben Sie trust_env=False äquivalent, damit Requests HTTP_PROXY und HTTPS_PROXY ignoriert. Dies ist die Lösung, wenn ein Proxy in einer Shell funktioniert, aber in einer anderen ProxyError auslöst, oder wenn eine Unternehmensvariable einen Scraper kapert, den Sie nicht konfiguriert haben, um einen Proxy zu verwenden.
Ist ConnectTimeout sicher wiederholbar?
Ja — die Requests-Dokumentation markiert ConnectTimeout als sicher wiederholbar, da die Anfrage den Server nie erreicht hat, sodass keine Nebenwirkung aufgetreten sein konnte. Wiederholen Sie es, idealerweise über ein rotierendes Gateway, sodass der nächste Versuch einen anderen, schnelleren Exit verwendet. ReadTimeout ist riskanter, blind auf nicht-idempotente Methoden wie POST zu wiederholen.
Sobald Sie aufhören, ProxyError als einzelnen Fehler zu behandeln, und anfangen, ihn nach Lebenszyklusphase zu lesen, sind die Lösungen mechanisch: Schema-Tippfehler werden vor dem Netzwerk ausgelöst, Verbindungsfehler benennen einen toten Proxy, SSL-Fehler benennen einen falschen Schlüssel, und intermittierende Fehler erfordern Rotation, keinen Neustart. Saubere Exits beseitigen die meisten von ihnen vollständig.