Wenn Sie Websites parsen oder Anfragen über Proxys in Python automatisieren, werden Sie früher oder später mit drei
klassischen Fehlern konfrontiert: ProxyError,
SSLError: WRONG_VERSION_NUMBER und HTTP
407 Proxy Authentication Required. In diesem Artikel werden wir
die Ursache jedes einzelnen Fehlers untersuchen und funktionierenden Code zur Behebung bereitstellen.
Wie requests mit Proxys funktioniert: Grundsyntax
Die Bibliothek requests akzeptiert Proxys über ein Dictionary
proxies, wobei die Schlüssel die Anfrage-Schemata
(http und https)
sind und die Werte die URL des Proxy-Servers mit optionaler Authentifizierung.
import requests
proxies = {
"http": "http://user:password@proxy_host:port",
"https": "http://user:password@proxy_host:port",
}
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.json())
Beachten Sie: Selbst für HTTPS-Anfragen wird das Proxy-Schema normalerweise als
http:// angegeben, da die meisten Proxy-Server
den CONNECT-Tunnel über das HTTP-Protokoll akzeptieren und nicht in SSL einwickeln. Wenn Sie
https:// für einen Proxy angeben, der dies nicht unterstützt, erhalten Sie
genau SSLError, dessen Analyse weiter unten folgt.
Wenn Sie mit SOCKS5-Proxys arbeiten, benötigen Sie ein zusätzliches Paket:
pip install requests[socks]
# Und die Syntax für Proxys ändert sich:
proxies = {
"http": "socks5://user:password@proxy_host:port",
"https": "socks5://user:password@proxy_host:port",
}
ProxyError: Ursachen und Lösungen
requests.exceptions.ProxyError ist eine Wrapper-Exception für
niedrigstufige Netzwerkfehler, die beim Versuch, eine Verbindung zu einem Proxy-Server herzustellen, auftreten. Am häufigsten
treten vier Szenarien auf.
1. Proxy nicht verfügbar oder Adresse/Port falsch angegeben
requests.exceptions.ProxyError: HTTPSConnectionPool(host='example.com', port=443):
Max retries exceeded with url: / (Caused by ProxyError('Cannot connect to proxy.',
ConnectionResetError(104, 'Connection reset by peer')))
Überprüfen Sie, ob Host und Port korrekt eingegeben sind und ob der Proxy-Server tatsächlich läuft. Der schnellste Weg zur Diagnose ist,
zu versuchen, sich über curl zu verbinden:
curl -x http://user:password@proxy_host:port https://httpbin.org/ip -v
2. Proxy hat Ihre Anfrage blockiert (IP- oder User-Agent-Sperre)
Rechenzentrums-Proxys werden häufig von Zielwebsites gesperrt, da ihre IP-Bereiche den Anti-Fraud-Systemen bekannt sind. Wenn der Fehler stabil auftritt, wenn Sie auf eine bestimmte Website zugreifen (z. B. Wildberries, Ozon oder soziale Netzwerke), und nicht auf allen Websites gleichzeitig, liegt das Problem nicht am Proxy selbst, sondern an dessen Reputation. In diesem Fall hilft der Wechsel zu residential Proxys — sie verwenden IPs echter Benutzer und werden seltener von Anti-Fraud-Systemen blockiert.
3. Limit der gleichzeitigen Verbindungen überschritten
Wenn Sie ein mehrstufiges Parsing durchführen und Hunderte von Verbindungen über denselben Proxy öffnen, kann der Server
beginnen, überflüssige Verbindungen zurückzusetzen. Die Lösung besteht darin, einen Verbindungs-Pool über
requests.adapters.HTTPAdapter mit einer Begrenzung von
pool_maxsize und
max_retries zu verwenden:
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retries = Retry(total=3, backoff_factor=1, status_forcelist=[502, 503, 504])
adapter = HTTPAdapter(max_retries=retries, pool_connections=20, pool_maxsize=20)
session.mount("http://", adapter)
session.mount("https://", adapter)
response = session.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
4. Timeout auf der Seite des Proxy-Servers
Wenn der Proxy "hängt" länger als der festgelegte Timeout, sehen Sie
ProxyError, eingewickelt in
ReadTimeoutError. Erhöhen Sie den Timeout auf einen angemessenen Wert
(normalerweise sind 15-30 Sekunden ausreichend) und fügen Sie eine separate Ausnahmebehandlung hinzu:
try:
response = requests.get(url, proxies=proxies, timeout=20)
except requests.exceptions.ProxyError as e:
print(f"Problem mit dem Proxy: {e}")
except requests.exceptions.Timeout:
print("Der Proxy hat innerhalb der vorgegebenen Zeit nicht geantwortet")
SSLError WRONG_VERSION_NUMBER: Problemanalyse
Dieser Fehler ist auf den ersten Blick einer der unverständlichsten, hat aber in der Tat fast immer einen Grund.
requests.exceptions.SSLError: HTTPSConnectionPool(host='example.com', port=443):
Max retries exceeded with url: / (Caused by SSLError(SSLError(1, '[SSL:
WRONG_VERSION_NUMBER] falsche Versionsnummer (_ssl.c:1123)')))
WRONG_VERSION_NUMBER bedeutet, dass der Client versucht hat, ein
SSL/TLS-Handshake durchzuführen, während der Server normalen HTTP-Verkehr (ohne Verschlüsselung) erwartet. Am häufigsten liegt der Grund in einer falsch
angegebenen Proxy-Schema im Dictionary proxies.
Häufiger Fehler: Angabe von https:// anstelle von
http:// in der Adresse des Proxy-Servers. Die meisten HTTP(S)-Proxys
akzeptieren Verbindungen über normales HTTP, selbst wenn sie HTTPS-Verkehr über den CONNECT-Mechanismus proxieren.
# FALSCH — verursacht WRONG_VERSION_NUMBER
proxies = {
"http": "https://user:password@proxy_host:port",
"https": "https://user:password@proxy_host:port",
}
# RICHTIG
proxies = {
"http": "http://user:password@proxy_host:port",
"https": "http://user:password@proxy_host:port",
}
Ein zweiter häufiger Grund ist ein Port, der physisch kein TLS unterstützt. Wenn der Proxy-Anbieter beispielsweise Port 8080 nur für HTTP-Verkehr reserviert hat und Sie versuchen, eine TLS-Verbindung direkt (ohne CONNECT) herzustellen, wird der Server mit normalem Text anstelle eines TLS-Handshakes antworten, und die OpenSSL-Clientbibliothek wird genau diesen Fehler ausgeben. Überprüfen Sie in der Dokumentation Ihres Proxy-Anbieters, welche Ports und Protokolle (HTTP/HTTPS/SOCKS5) an jedem einzelnen Port verfügbar sind.
Eine dritte Möglichkeit ist, dass Sie socket oder externe
Bibliotheken für eine direkte TCP-Verbindung mit dem Proxy verwenden, wobei Sie den Standardmechanismus von requests umgehen. In diesem Fall stellen Sie sicher, dass
die TLS-Wicklung nur für die tatsächliche Zielwebsite und nicht für die Verbindung zum Proxy angewendet wird.
407 Proxy Authentication Required: Authentifizierung
Der Antwortcode 407 ist das Äquivalent zu 401, jedoch für Proxy-Server. Er bedeutet, dass der Server eine Authentifizierung verlangt, die Sie entweder nicht übermittelt haben oder in falschem Format übermittelt haben.
Methode 1: Benutzername und Passwort direkt in der URL
proxies = {
"http": "http://login:password@proxy_host:port",
"https": "http://login:password@proxy_host:port",
}
response = requests.get("https://httpbin.org/ip", proxies=proxies)
Diese Methode ist die einfachste, aber wenn im Benutzernamen oder Passwort Sonderzeichen enthalten sind (z. B. @,
:, /),
müssen sie über urllib.parse.quote maskiert werden:
from urllib.parse import quote
login = quote("user@domain")
password = quote("p@ssw:ord!")
proxy_url = f"http://{login}:{password}@proxy_host:port"
proxies = {"http": proxy_url, "https": proxy_url}
Methode 2: Proxy-Authorization-Header manuell
Wenn der Proxy-Anbieter ein nicht standardmäßiges Authentifizierungsschema verwendet oder Sie mehr Kontrolle benötigen, können Sie den Header manuell über Base64-Codierung zusammenstellen:
import base64
import requests
login = "user"
password = "password"
credentials = base64.b64encode(f"{login}:{password}".encode()).decode()
headers = {
"Proxy-Authorization": f"Basic {credentials}"
}
proxies = {
"http": "http://proxy_host:port",
"https": "http://proxy_host:port",
}
response = requests.get(
"https://httpbin.org/ip",
proxies=proxies,
headers=headers,
timeout=10
)
Wichtig: Einige Proxy-Anbieter binden die Authentifizierung nicht an Benutzername/Passwort, sondern an eine bestimmte statische IP des Clients (Whitelist). Wenn Sie die IP ändern (z. B. über VPN oder dynamische IP des Anbieters), kann der 407-Fehler selbst bei korrekten Anmeldedaten auftreten — weil Ihre aktuelle externe IP nicht auf der Whitelist des Proxys steht. Die Lösung besteht darin, sich in das persönliche Konto des Anbieters einzuloggen und die Liste der erlaubten IPs zu aktualisieren oder auf Authentifizierung über Benutzername/Passwort anstelle von IP-Whitelist umzuschalten.
Retry-Logik und Ausnahmebehandlung
In der Praxis sind Proxy-Fehler selten einmalige Ereignisse — insbesondere beim massenhaften Parsen. Eine korrekte Code-Architektur sollte Wiederholungsversuche mit Verzögerung und Protokollierung jedes Fehlers separat vorsehen.
import time
import requests
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def fetch_with_retry(url, proxies, max_retries=3, backoff=2):
for attempt in range(1, max_retries + 1):
try:
response = requests.get(url, proxies=proxies, timeout=15)
response.raise_for_status()
return response
except requests.exceptions.ProxyError as e:
logger.warning(f"[Versuch {attempt}] ProxyError: {e}")
except requests.exceptions.SSLError as e:
logger.warning(f"[Versuch {attempt}] SSLError: {e}")
except requests.exceptions.HTTPError as e:
if response.status_code == 407:
logger.error("407: Überprüfen Sie Benutzername/Passwort oder Whitelist-IP des Proxys")
break
logger.warning(f"[Versuch {attempt}] HTTPError: {e}")
except requests.exceptions.Timeout:
logger.warning(f"[Versuch {attempt}] Verbindungs-Timeout")
time.sleep(backoff * attempt)
raise RuntimeError(f"Fehler beim Abrufen von {url} nach {max_retries} Versuchen")
Dieser Ansatz spart Stunden der Fehlersuche: Anstatt dass das Skript beim ersten Netzwerkproblem abstürzt, erhalten Sie ein verständliches Protokoll mit dem spezifischen Fehler-Typ bei jedem Versuch.
Proxy-Rotation und Bekämpfung von Sperren
Während ProxyError und 407 häufig mit den Code-Einstellungen zusammenhängen, deuten massenhafte Sperren und stabile Verbindungsabbrüche bei bestimmten Domains fast immer auf ein Problem mit der Qualität des IP-Pools hin. Für Aufgaben wie das Parsen von Marktplätzen (Wildberries, Ozon, Avito) oder die Arbeit mit sozialen Netzwerken wird empfohlen, die IP bei jeder Anfrage oder über einen festgelegten Zeitraum zu rotieren.
import random
proxy_pool = [
"http://user:[email protected]:8000",
"http://user:[email protected]:8000",
"http://user:[email protected]:8000",
]
def get_random_proxy():
proxy = random.choice(proxy_pool)
return {"http": proxy, "https": proxy}
response = requests.get(url, proxies=get_random_proxy(), timeout=15)
Für Produktionsparser ist es in der Regel bequemer, Proxys mit automatischer Rotation auf der Seite des Anbieters zu verwenden — dann müssen Sie die IP-Liste nicht selbst speichern, die Rotation erfolgt transparent über einen Endpunkt. In diesem Fall residential Proxys mit Rotation eignen sich besonders gut, um Anti-Bot-Schutz auf Websites mit strengen Erkennungssystemen zu umgehen, während Rechenzentrums-Proxys eine gute Wahl sind, wenn die Geschwindigkeit der Anfragen wichtig ist und die Zielwebsite nicht aggressiv Rechenzentrumsbereiche blockiert.
| Proxy-Typ | Geschwindigkeit | Sperrrisiko | Aufgaben |
|---|---|---|---|
| Rechenzentrums-Proxys | Hoch | Mittel-hoch | Schnelles Parsen öffentlicher APIs |
| Residential Proxys | Mittel | Niedrig | Parsing von Marktplätzen, sozialen Netzwerken |
| Mobile Proxys | Mittel-niedrig | Minimal | Arbeiten mit strengen Anti-Bot-Systemen |
Session, Timeouts und SSL-Überprüfung
Für langlebige Skripte (z. B. zyklische Parser) sollte requests.Session() anstelle von einzelnen Aufrufen
requests.get() verwendet werden. Die Session wiederverwendet TCP-Verbindungen,
was die Belastung des Proxy-Servers verringert und die Anzahl der ProxyErrors bei großen Anfragevolumina reduziert.
session = requests.Session()
session.proxies.update({
"http": "http://user:password@proxy_host:port",
"https": "http://user:password@proxy_host:port",
})
for url in urls_list:
try:
resp = session.get(url, timeout=15)
print(resp.status_code, url)
except requests.exceptions.RequestException as e:
print(f"Fehler bei {url}: {e}")
Besonders erwähnenswert ist der Parameter verify. Wenn Sie mit einem Proxy arbeiten,
der das SSL-Zertifikat selbst ersetzt (MITM-Proxy zur Fehlersuche oder einige Unternehmensproxies),
kann requests über die Nichtübereinstimmung des Zertifikats meckern. Die vollständige Deaktivierung der Überprüfung
(verify=False) sollte nur in einer Testumgebung erfolgen — in der Produktion
birgt dies das Risiko von "Man-in-the-Middle"-Angriffen:
# Nur für lokale Fehlersuche!
response = requests.get(url, proxies=proxies, verify=False, timeout=15)
# Der richtige Weg — den Pfad zu einem vertrauenswürdigen Zertifikat des Proxys angeben
response = requests.get(url, proxies=proxies, verify="/path/to/proxy_cert.pem")
Fehlerdiagnose-Checkliste
Wenn das Skript mit einem Proxy-Fehler abstürzt, gehen Sie diese Liste von oben nach unten durch — in 90% der Fälle finden Sie die Ursache in den ersten drei Punkten.
- Überprüfen Sie das Schema im Dictionary
proxies— es sollte fast immerhttp://sein, selbst für HTTPS-Anfragen. - Testen Sie den Proxy direkt über
curl -x, um ein Problem auf der Code-Seite auszuschließen. - Stellen Sie sicher, dass Benutzername und Passwort keine nicht maskierten Sonderzeichen in der URL enthalten.
- Überprüfen Sie, ob der Proxy an eine bestimmte IP (Whitelist) gebunden ist, anstelle von Authentifizierung über Benutzername/Passwort.
- Erhöhen Sie den
timeoutauf 15-30 Sekunden, bevor Sie den Proxy als nicht funktionsfähig betrachten. - Wenn der Fehler nur auf einer bestimmten Website auftritt — das Problem liegt in der Reputation der IP und nicht im Code.
- Fügen Sie eine Retry-Logik mit exponentieller Verzögerung hinzu, anstatt nur einmalige Versuche zu unternehmen.
- Verwenden Sie bei massenhaften Parsen IP-Rotation und nicht einen statischen Proxy für alle Anfragen.
Fazit
Die meisten Proxy-Fehler in Python requests lassen sich auf drei Dinge zurückführen: ein falsches Schema in der Proxy-URL
(http anstelle von https),
fehlende oder falsche Authentifizierungsformate und die Qualität des IP-Pools selbst. ProxyError deutet normalerweise auf ein Verbindungsproblem
oder eine IP-Sperre hin, SSLError WRONG_VERSION_NUMBER weist fast immer auf ein falsches Proxy-Schema hin, und 407 —
auf ein Problem mit Benutzername/Passwort oder Whitelist.
Wenn Sie regelmäßig mit Sperren und 407-Fehlern beim Parsen von Marktplätzen oder sozialen Netzwerken konfrontiert sind, sollten Sie die Quelle des Proxys selbst überdenken und nicht nur den Code. Für stabiles Parsen mit einer niedrigen Blockierungsrate empfehlen wir, residential Proxys auszuprobieren — sie verwenden echte IP-Adressen und verursachen deutlich seltener ProxyErrors auf geschützten Websites. Wenn jedoch Geschwindigkeit und Anfragevolumen wichtiger sind als das Umgehen komplexer Anti-Bot-Systeme, sollten Sie sich die Rechenzentrums-Proxys ansehen — sie sind günstiger und schneller für einfache Parsing-Aufgaben.