Zurück zum Blog
Anleitungen
Ștefan RăcilăLast updated on May 7, 202610 min read

Wie man Proxies mit Python-Requests verwendet: Von der Basis bis zur Produktion

Wie man Proxies mit Python-Requests verwendet: Von der Basis bis zur Produktion
Kurzfassung: Dieser Leitfaden erklärt Schritt für Schritt, wie man Proxys mit Python Requests von Anfang bis Ende einsetzt: ein funktionierendes proxies Dict, authentifizierte URLs, Umgebungsvariablen, Session Wiederverwendung, SOCKS5 ohne DNS-Lecks sowie einen Rotationspool mit Wiederholungsversuchen und einem Circuit Breaker. Am Ende werden Sie wissen, wann sich eine verwaltete API gegenüber einem selbst erstellten Pool bezahlt macht.

Einleitung

Wenn Sie schon einmal einen Scraper veröffentlicht haben, der lokal funktionierte, dann aber in der Produktion 403er- oder 429er-Fehler oder stille Timeouts zurückgab, wissen Sie bereits, warum es Proxys gibt. Zu lernen, wie man Proxys mit Python Requests einsetzt, macht den Unterschied zwischen einem Skript, das einmal auf Ihrem Laptop läuft, und einem Job, der Rate Limits, Geoblocking und IP-Sperren über Tausende von Seiten hinweg übersteht.

Eine Python-Requests-Proxy-Konfiguration ist im einfachsten Fall ein Wörterbuch, das http und https einer Proxy-URL zuordnet und an requests.get(). Damit sind Sie für zehn Minuten entsperrt. Die Produktion erfordert mehr: Anmeldedaten, die nicht in Git gespeichert werden, Sitzungen, die Cookies beibehalten, SOCKS5-Endpunkte, die kein DNS preisgeben, Wiederholungsversuche mit Backoff und eine Rotationsstrategie, die nicht ständig auf einen toten Proxy zugreift.

Dieser Leitfaden richtet sich an fortgeschrittene Python-Entwickler, die bereits die Grundlagen von requests und nun einen zuverlässigen Weg suchen, um Proxy-Unterstützung hinzuzufügen, ohne ihren Scraper neu schreiben zu müssen. Wir behandeln die Verwendung von Proxys mit Python Requests, vom einfachen Wörterbuch bis hin zu einer Rotationsschleife für den Produktionsbetrieb, wobei die Vor- und Nachteile in einfacher Sprache erläutert werden.

Schnellstart: Ein funktionierender Python-Requests-Proxy in fünf Minuten

Bevor wir uns eingehend mit Rotation und Wiederholungsversuchen befassen, hier das achtzeilige Beispiel, das 90 % der Entwickler tatsächlich benötigen, wenn sie nachschlagen, wie man Proxys mit Python Requests verwendet. Fügen Sie es in eine Datei ein, ersetzen Sie die Angaben durch einen beliebigen funktionierenden Proxy-Host:Port und führen Sie es aus.

import requests

proxies = {
    "http":  "http://203.0.113.10:8080",
    "https": "http://203.0.113.10:8080",
}

resp = requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=10)
print(resp.json())

Wenn die ausgegebene IP-Adresse die des Proxys und nicht Ihre eigene ist, befindet sich Ihr Proxy im Request-Pfad. Der Rest dieses Leitfadens befasst sich mit der Absicherung dieses Musters.

Voraussetzungen: Python, pip und ein Proxy, auf den du zugreifen kannst

Sie benötigen Python 3.8 oder höher (python --version), pip) sowie mindestens einen funktionsfähigen Proxy-Host:Port. Eine virtuelle Umgebung (python -m venv venv) sorgt für übersichtliche Abhängigkeiten pro Projekt. Installieren Sie Requests mit pip install requests. Der Proxy kann aus einer kostenlosen Liste, einem kostenpflichtigen Pool oder einer lokalen Squid- oder Tor-Instanz stammen.

So verwenden Sie Proxys mit Python Requests: das mentale Modell

Bevor man sich mit dem Code befasst, ist es hilfreich zu wissen, wie Requests tatsächlich entscheidet, wohin der Datenverkehr gesendet wird. Die Bibliothek leitet jeden Aufruf schemenbasiert über eine Proxy-URL weiter: HTTP, HTTPS und (mit einem zusätzlichen Paket) SOCKS. Drei Quellen können diese URL bereitstellen, in dieser groben Rangfolge: das proxies= Argument bei einem einzelnen Aufruf, das session.proxies dict bei einem Sessionund schließlich die HTTP_PROXY / HTTPS_PROXY Umgebungsvariablen. Die genaue Priorität und die Behandlung von Kleinbuchstabenvarianten sind in der Dokumentation zur erweiterten Verwendung von Requests dokumentiert; überprüfen Sie dies immer anhand Ihrer festgehaltenen Version.

Einrichten eines einfachen Proxys mit Python Requests

Die grundlegende Einrichtung erfolgt in zwei Schritten: Erstellen Sie ein proxies Wörterbuch und senden Sie anschließend eine Verifizierungsanfrage darüber. Die nächsten beiden Unterabschnitte führen Sie durch jeden Schritt und zeigen die Fallstricke auf, die bei nicht funktionierenden oder falsch konfigurierten Proxys auftreten können.

Erstellen Sie das Proxy-Wörterbuch für HTTP und HTTPS

In Python Requests werden Proxys als Wörterbuch übergeben, das Schemata einer Proxy-URL zuordnet. Füllen Sie immer beide Schlüssel aus, auch wenn Sie nur HTTPS-Ziele ansteuern möchten, da Weiterleitungen das Schema herabstufen können.

proxies = {
    "http":  "http://user:pass@proxy.example.com:8080",
    "https": "http://user:pass@proxy.example.com:8080",
}
requests.get(url, proxies=proxies, timeout=(5, 15))

Das timeout=(connect, read) Tupel ist in der Produktion unverzichtbar. Ohne dieses Tupel führt ein nicht funktionierender Proxy zum Absturz Ihres Workers.

Überprüfen Sie, ob der Proxy im Request-Pfad enthalten ist

Rufe einen IP-Echo-Endpunkt auf und vergleiche die Antwort mit deiner tatsächlichen IP-Adresse. Zwei zuverlässige Dienste sind https://api.ipify.org?format=json und https://httpbin.org/ip.

print(requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=10).json())

Wenn die zurückgegebene Adresse von Ihrer lokalen IP abweicht, funktioniert der Proxy. Wenn sie übereinstimmt, ist der Proxy stillschweigend fehlgeschlagen.

Proxys authentifizieren und Anmeldedaten schützen

Die meisten kostenpflichtigen Proxys sind authentifiziert, und genau hier wird die Verwendung von Proxys mit Python Requests komplizierter. Die nächsten drei Unterabschnitte behandeln URL-Einbettung, Umgebungsvariablen und die drei Fehlercodes, die dir angezeigt werden.

Benutzername und Passwort in die Proxy-URL einbetten

Das akzeptierte Format lautet http://user:pass@host:port. Wenn Ihr Passwort @, :, %, oder /enthält, müssen Sie es URL-kodieren, da Requests die URL sonst falsch interpretiert und Sie 407-Fehler erhalten:

from urllib.parse import quote
user = quote("alice@corp")
pwd  = quote("p@ss:w/rd%1")
proxy_url = f"http://{user}:{pwd}@proxy.example.com:8080"

Committen Sie diese Zeichenfolge niemals in Git.

Verschieben Sie Geheimnisse in HTTP_PROXY, HTTPS_PROXY und NO_PROXY

Requests übernimmt diese automatisch HTTP_PROXY, HTTPS_PROXYund NO_PROXY aus der Umgebung und berücksichtigt laut offizieller Dokumentation auf POSIX-Systemen auch Kleinbuchstabenvarianten. Das bedeutet, dass du Anmeldedaten vollständig aus dem Code heraushalten kannst:

# Linux / macOS
export HTTPS_PROXY="http://user:pass@proxy.example.com:8080"
export NO_PROXY="localhost,127.0.0.1,.internal"
# Windows
setx HTTPS_PROXY "http://user:pass@proxy.example.com:8080"

Dies ist das sauberste Muster für Docker-Images und CI-Runner, bei denen Geheimnisse in der Umgebung und nicht im Repo liegen.

Proxy-Fehler 407, 401 und 403 diagnostizieren

Wenn etwas nicht stimmt, zeigt Ihnen der Statuscode an, welche Ebene Probleme bereitet.

Status

Mögliche Ursache

Einzeilige Lösung

407 Proxy-Authentifizierung erforderlich

Fehlende oder fehlerhafte Proxy-Anmeldedaten

Passwort URL-kodieren und erneut testen

401 Nicht autorisiert

Falscher Benutzername oder falsches Passwort

Wechseln Sie die Anmeldedaten und überprüfen Sie mit curl -x

403 Zugriff verweigert

Zielseite hat die Proxy-IP blockiert

Wechseln Sie zu einem anderen Proxy oder ändern Sie die Region

Überprüfen Sie zuerst den Proxy, dann die Zielseite.

Verwenden Sie die Einstellungen mit requests.Session für Cookies und Connection Pooling

A Session ist die richtige Funktion, sobald Sie mehr als einen Aufruf tätigen. Sie speichert proxies, Standard-Header und Cookies und hält die zugrunde liegende TCP-Verbindung aufrecht, sodass du nicht bei jedem Aufruf einen neuen TLS-Handshake durchführen musst. Session ist in Requests integriert, es muss also nichts zusätzlich installiert werden.

session = requests.Session()
session.proxies = proxies
session.headers.update({"User-Agent": "my-scraper/1.0"})

session.post("https://example.com/login", data={"u": "alice", "p": "secret"})
dashboard = session.get("https://example.com/dashboard")  # cookies persist
print(dashboard.status_code, len(dashboard.content))

Dieselbe Sitzung deckt .text, .json()und .content, sodass Text-, JSON- und Binär-Downloads alle ohne Neukonfiguration über denselben Python-Requests-Session-Proxy laufen.

Verwenden Sie SOCKS5-Proxys über requests[socks]

Requests unterstützt SOCKS standardmäßig nicht. Binden Sie PySocks mit dem socks extra:

pip install "requests[socks]"

Verwenden Sie dann das socks5h:// Schema. Das abschließende h weist PySocks an, DNS über den Proxy statt lokal aufzulösen – genau das, was du willst, wenn du dem Resolver deines Internetanbieters nicht vertraust oder über Tor surfst.

proxies = {
    "http":  "socks5h://127.0.0.1:9050",  # Tor default
    "https": "socks5h://127.0.0.1:9050",
}
requests.get("https://check.torproject.org/", proxies=proxies, timeout=15)

Plain socks5:// löst DNS lokal auf und gibt die von dir besuchten Hostnamen unbemerkt weiter.

Proxys rotieren, um Sperren und Ratenbegrenzungen zu vermeiden

Eine einzelne IP-Adresse wird einer Ratenbegrenzung unterzogen und schließlich gesperrt. Die eigentliche Lösung für den groß angelegten Einsatz von Proxys mit Python Requests ist die Rotation, und die nächsten drei Unterabschnitte zeigen Muster zunehmender Reife.

Zufällige Rotation mit einer Wiederholungsschleife

Das einfachste Muster ist random.choice über eine Liste von Proxys, eingebettet in eine Wiederholungsschleife:

import random, requests
from requests.exceptions import RequestException

PROXIES = [{"http": p, "https": p} for p in PROXY_URLS]

def fetch(url, attempts=4):
    for _ in range(attempts):
        proxy = random.choice(PROXIES)
        try:
            return requests.get(url, proxies=proxy, timeout=10)
        except RequestException:
            continue
    raise RuntimeError("all attempts failed")

Es funktioniert, aber reine Zufälligkeit wählt gerne wiederholt tote Proxys aus und ignoriert die Auslastung.

Auswahl nach Zweierpotenzen für intelligenteren Lastausgleich

Eine gut untersuchte Verfeinerung sind Zweierpotenz-Entscheidungen: Für jede Anfrage werden zwei Proxys zufällig ausgewählt und derjenige verwendet, der derzeit weniger laufende Aufrufe verarbeitet. Die Intuition, die durch die Literatur zum Lastausgleich gestützt wird und gemeinhin Mitzenmachers Analyse aus dem Jahr 2001 zugeschrieben wird, ist, dass dies die Last im Worst-Case-Szenario weitaus besser dämpft als eine gleichmäßige Zufallsauswahl, während der Aufwand gering bleibt.

import random
LOAD = {p: 0 for p in PROXY_URLS}

def pick():
    a, b = random.sample(PROXY_URLS, 2)
    return a if LOAD[a] <= LOAD[b] else b

Erhöhen LOAD[proxy] vor der Anfrage und dekrementieren Sie danach. Die genauen Gewinne hängen von der Poolgröße ab; führen Sie einen Benchmark durch, bevor Sie Zahlen nennen.

Fügen Sie einen Circuit Breaker hinzu, damit inaktive Proxys keine Anfragen mehr verschwenden

Sowohl bei der Zufallsauswahl als auch bei der Zweierpotenz-Auswahl wird so lange ein ausgefallener Proxy ausgewählt, bis er erfolgreich ist. Ein Circuit Breaker behebt dieses Problem. Verfolgen Sie den Status pro Proxy: CLOSED (intakt), OPEN (übersprungen) und HALF_OPEN (auf Bewährung).

import time
state = {p: {"fail": 0, "open_until": 0} for p in PROXY_URLS}
MAX_FAILS, COOLDOWN = 3, 60

def usable(p):
    return time.time() >= state[p]["open_until"]

def record(p, ok):
    if ok:
        state[p]["fail"] = 0
    else:
        state[p]["fail"] += 1
        if state[p]["fail"] >= MAX_FAILS:
            state[p]["open_until"] = time.time() + COOLDOWN

Nach der Abklingzeit sollte der Proxy eine Probeanfrage erhalten, bevor er vollständig wiederhergestellt wird.

Wiederholen Sie fehlgeschlagene Anfragen mit HTTPAdapter und urllib3 Wiederholen

Einbinden eines HTTPAdapter mit einer urllib3 Retry Richtlinie auf eine Session wendet Wiederholungsversuche auf jeden HTTP- und HTTPS-Aufruf aus dieser Session an. Pin urllib3 (z. B. urllib3==2.2.*), damit die Parameternamen über Upgrades hinweg stabil bleiben.

from requests import Session
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry = Retry(
    total=3,
    status_forcelist=[429, 500, 502, 503, 504],
    backoff_factor=2,
    allowed_methods=["GET", "POST"],
    respect_retry_after_header=True,
)
adapter = HTTPAdapter(max_retries=retry)
s = Session()
s.mount("http://", adapter)
s.mount("https://", adapter)

Mit backoff_factor=2wartet urllib3 zwischen den Versuchen etwa backoff_factor * (2 ** (n - 1)) Sekunden zwischen den Versuchen (etwa 2, 4, 8 s). Kombinieren Sie Wiederholungsversuche mit der Rotation, damit bei jedem Wiederholungsversuch auch ein neuer Proxy ausgewählt wird.

Behandlung der SSL-Überprüfung und selbstsignierter Proxy-Zertifikate

Wenn ein Proxy ein selbstsigniertes Zertifikat vorlegt, verify=False unterdrückt die Warnung, macht Sie jedoch anfällig für Man-in-the-Middle-Angriffe; verwenden Sie diese Funktion daher nur bei vertrauenswürdigen lokalen Proxys oder in Tests. Die sicherere Lösung besteht darin, den Proxy oder das Unternehmens-CA-Bundle über verify="/path/to/ca.pem" oder REQUESTS_CA_BUNDLE. Unterdrücken Sie InsecureRequestWarning erst, nachdem Sie sich bewusst für diesen Sicherheitskompromiss entschieden haben.

Wann Sie den selbst erstellten Proxy-Pool gegen eine verwaltete Scraping-API eintauschen sollten

Führen Sie diese Checkliste durch. Wenn Sie drei oder mehr Punkte ankreuzen, ist ein verwalteter Proxy oder eine Scraping-API in der Regel kostengünstiger als Ihre Zeit:

  • Sie benötigen Geo-Targeting in mehr als zwei Ländern.
  • Sperren kosten echte Einnahmen, nicht nur einen erneuten Versuch.
  • Ziele rendern Inhalte mit JavaScript.
  • Ein leitender Ingenieur verbringt einen Tag pro Woche damit, den Pool zu betreuen.
  • Die Compliance verlangt geprüfte private IP-Adressen.

Wichtige Erkenntnisse

  • Die kürzeste Antwort auf die Frage, wie man Proxys mit Python Requests verwendet, ist ein Dict, das http und https auf eine Proxy-URL, die über proxies= mit einem timeout.
  • Halten Sie Anmeldedaten aus dem Quellcode heraus: Bevorzugen Sie HTTP_PROXY, HTTPS_PROXY, sowie NO_PROXY Umgebungsvariablen, sowie die URL-Kodierung von Sonderzeichen in Passwörtern.
  • Ein requests.Session speichert Proxys, Header und Cookies und verwendet TCP-Verbindungen wieder, was die richtige Standardeinstellung für jeden Workflow mit mehreren Aufrufen ist.
  • Die Produktionsrotation kombiniert „Power-of-Two“-Auswahlmöglichkeiten mit einem Circuit Breaker und einer HTTPAdapter Retry Richtlinie, die 429er- und 5xx-Fehler übersteht.
  • Für SOCKS5 installieren Sie requests[socks] und verwenden Sie socks5h:// , damit DNS über den Proxy aufgelöst wird, anstatt lokal zu lecken.

Verwandte WebScrapingAPI-Ressourcen

FAQ

Unterstützt Python Requests SOCKS5-Proxys von Haus aus?

Nein. Die Basisinstallation requests Installation bietet nur HTTP- und HTTPS-Unterstützung. Führen Sie pip install "requests[socks]" , um PySocks einzubinden, und verwenden Sie dann socks5:// oder, besser noch, socks5h:// eine URL in Ihrem proxies dict. Das ist der sauberste Weg zur SOCKS-Unterstützung.

Warum wird meine echte IP-Adresse bei meinen über einen Proxy gesendeten Anfragen immer noch durch DNS-Lookups preisgegeben?

Weil das socks5:// Schema PySocks anweist, Hostnamen lokal aufzulösen, bevor die Verbindung getunnelt wird. Wechsle zu socks5h://, wo das abschließende h für die Auflösung des Hostnamens auf dem Remote-Server steht, sodass DNS-Abfragen über den SOCKS-Server laufen. Dies ist besonders wichtig für Tor oder jedes andere Bedrohungsszenario, bei dem Ihr DNS-Resolver nicht vertrauenswürdig ist oder Protokolle führt.

Wie URL-kodiere ich ein Proxy-Passwort, das die Zeichen @, : oder % enthält?

Verwenden Sie urllib.parse.quote aus der Standardbibliothek: quote("p@ss:w/rd%1") wird zu p%40ss%3Aw%2Frd%251. Betten Sie den kodierten Wert in http://user:encoded_pwd@host:port. Ohne Kodierung beenden diese Zeichen das User-Info-Segment vorzeitig, und Sie erhalten einen 407 Proxy Authentication Required, selbst wenn das Passwort technisch korrekt ist.

Wie weise ich Python Requests an, den Proxy für localhost oder interne Domänen zu überspringen?

Setzen Sie NO_PROXY auf eine durch Kommas getrennte Liste von Hosts oder Domainsuffixen, zum Beispiel NO_PROXY="localhost,127.0.0.1,.internal,.svc.cluster.local". Requests berücksichtigt auf POSIX-Systemen Groß- und Kleinschreibung. Für Übersteuerungen pro Aufruf übergeben Sie proxies={"http": None, "https": None} , um alle Proxys auf Sitzungsebene zu umgehen.

Wann sollte ich von einem selbstverwalteten rotierenden Proxy-Pool zu einer verwalteten Scraping-API wechseln?

Wenn die Betriebskosten die Kosten übersteigen. Konkrete Auslöser: Sperren kosten mehr als ein erneuter Versuch, Sie benötigen private IP-Adressen in mehreren Ländern, die Ziele sind JavaScript-lastig oder Sie verbringen mehr als ein paar Stunden pro Woche mit der Optimierung des Pools. Unterhalb dieser Schwelle reicht ein kleiner selbstverwalteter Pool mit Wiederholungsversuchen und einem Circuit Breaker in der Regel aus.

Fazit

Bei der Verwendung von Proxys mit Python Requests geht es weniger um einen einzelnen Trick als vielmehr um die Schichtung: ein übersichtliches proxies dict für den Anfang, Anmeldedaten in Umgebungsvariablen, damit Geheimnisse aus Git herausbleiben, ein Session für die Wiederverwendung von Verbindungen und Cookies, socks5h:// wenn DNS-Leaks eine Rolle spielen, sowie Rotation und Wiederholungsversuche, wenn eine IP-Adresse nicht mehr ausreicht. Kombinieren Sie „Power-of-Two“-Entscheidungen mit einem Circuit Breaker und einer HTTPAdapter Retry Richtlinie, und Ihr Scraper bricht nicht mehr zusammen, sobald ein Proxy ausfällt oder ein Ziel 429-Fehler zurückgibt.

Irgendwann stößt jedes Team an die Grenze, an der der Betrieb des Pools mehr kostet, als die Daten wert sind. Wenn Ihre Ziele stark geschützt, geospezifisch oder JavaScript-gerendert sind, übernimmt eine verwaltete Option wie die WebScrapingAPI Scraper API die Anforderungsschicht, die Rotation und das Entsperren hinter einem einzigen Endpunkt, sodass Sie den bereits geschriebenen Parsing-Code beibehalten und lediglich den Abrufschritt austauschen können. Nutzen Sie die obige Checkliste zur Entscheidung; wenn drei oder mehr Kästchen angekreuzt sind, spricht die Kalkulation eher für eine verwaltete Infrastruktur als für einen weiteren Sprint zur Pool-Wartung. So oder so sollten die Muster in diesem Leitfaden dafür sorgen, dass Ihr requests-basierten Code vom Prototyp bis zur Produktion in einem einwandfreien Zustand halten.

Über den Autor
Ștefan Răcilă, Full-Stack-Entwickler @ WebScrapingAPI
Ștefan RăcilăFull-Stack-Entwickler

Stefan Racila ist DevOps- und Full-Stack-Entwickler bei WebScrapingAPI, wo er Produktfunktionen entwickelt und die Infrastruktur wartet, die für die Zuverlässigkeit der Plattform sorgt.

Los geht’s

Sind Sie bereit, Ihre Datenerfassung zu erweitern?

Schließen Sie sich den über 2.000 Unternehmen an, die WebScrapingAPI nutzen, um Webdaten im Unternehmensmaßstab ohne zusätzlichen Infrastrukturaufwand zu extrahieren.