Ohne KYC — keine ID, kein Selfie, keine Dokumente. Mit Krypto bezahlen: BTC, USDT, USDC, ETH, SOL, LTC
Sprache: Deutsch
Jetzt starten

Dokumentation · Python 3.9+ · requests · httpx · aiohttp

Rotierende Residential-Proxys in Python: requests, httpx und aiohttp

Produktionsmuster, keine Einzeiler: Wiederholungen, die Retry-After respektieren, eine neue IP pro Anfrage oder eine IP pro Ablauf, pro-Host Nebenläufigkeit in asyncio und die tatsächlich verbrauchten Bytes pro Seite.

Zuletzt aktualisiert: · 7 Min. Lesezeit

Kurze Antwort

Wie verwende ich rotierende Residential-Proxys in Python?

Übergebe http://USERNAME:[email protected]:7777 als Proxy für sowohl http als auch https in requests, als proxy= in httpx 0.26+ oder als proxy= pro Anfrage in aiohttp. CrawlRelay Residential-Proxys rotieren bei jeder neuen Verbindung und bleiben mit -session-<id> im Benutzernamen sticky. Sie kosten 1,50 $ für 1 GB und 0,50 $/GB ab 50 GB. Bezahlt mit Krypto, ohne KYC.

Python Einrichtung im Überblick

requestsproxies={"http": url, "https": url}; Wiederholungen über urllib3 Retry
httpxhttpx.Client(proxy=url); das alte proxies= Argument wurde in httpx 0.28 entfernt
aiohttpsession.get(url, proxy="http://USER:PASS@host:port"), Zugangsdaten in der Proxy-URL
SOCKS5pip install "requests[socks]" oder httpx[socks], dann socks5h:// auf Port 7778
Neue IP pro AnfrageKeep-alive deaktivieren: Connection: close, max_keepalive_connections=0 oder force_close=True
Gleiche IP für einen Ablauf-session-<id>-ttl-<minutes> im Benutzernamen, bis zu 30 Minuten
Proxy URL SchemaImmer http:// für den HTTP Port, auch bei HTTPS-Websites

Wie verwende ich einen Proxy mit requests und Wiederholungen, die Retry-After respektieren?

Montiere einen HTTPAdapter mit urllib3s Retry auf einer Session. Er wiederholt Verbindungsfehler und gelistete Statuscodes, wartet mit exponentiellem Backoff und respektiert den Retry-After Header, den Seiten bei 429 und 503 senden. Setze trust_env = False, damit eine übriggebliebene HTTPS_PROXY Variable deinen Proxy nicht überschreiben kann.

requests + urllib3 Retry
import os

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

USER = os.environ.get("CRAWLRELAY_USER", "USERNAME-country-us")
PASSWORD = os.environ.get("CRAWLRELAY_PASSWORD", "PASSWORD")
PROXY = "http://%s:%[email protected]:7777" % (USER, PASSWORD)

retry = Retry(
    total=4,
    connect=2,
    backoff_factor=1.0,  # waits of 0 s, 2 s, 4 s, 8 s (Retry-After wins on 429/503)
    status_forcelist=(429, 502, 503, 504),
    allowed_methods=frozenset({"GET", "HEAD"}),
    respect_retry_after_header=True,
)

session = requests.Session()
session.trust_env = False  # ignore HTTP(S)_PROXY from the environment
session.mount("http://", HTTPAdapter(max_retries=retry))
session.mount("https://", HTTPAdapter(max_retries=retry))
session.proxies = {"http": PROXY, "https": PROXY}
session.headers["User-Agent"] = "ExampleCrawler/1.0 (+https://example.com/crawler-info)"
session.headers["Connection"] = "close"  # new connection per request, so usually a new exit IP

r = session.get("https://api.ipify.org", timeout=(10, 30))
print(r.status_code, r.text)

Wie erstelle ich gezielt Proxy-URLs sicher?

Generiere den Benutzernamen in einer Funktion und validiere ihn. Ein Tippfehler im Ländercode oder ein nicht kodiertes Zeichen im Passwort erzeugt einen 407, der wie ein Anmeldeproblem aussieht. Der folgende Helfer hält die dokumentierte Reihenfolge (USERNAME-country-{cc}-state-{state}-city-{city}-zip-{zip}-asn-{asn}-session-{id}-ttl-{minutes}) ein, lehnt unbekannte Schlüssel ab und URL-kodiert beide Zugangsdaten.

Benutzernamen-Ersteller und Proxy-URL
import re
from urllib.parse import quote

ORDER = ("country", "state", "city", "zip", "asn", "session", "ttl")
VALUE = re.compile(r"^[a-z0-9_]+$")


def build_username(base, **params):
    """build_username("USERNAME", country="us", city="new_york", session="job1", ttl=30)"""
    parts = [base]
    for key in ORDER:
        value = params.pop(key, None)
        if value is None:
            continue
        value = str(value).lower()
        if not VALUE.match(value):
            raise ValueError("bad value for %s: %r" % (key, value))
        if key == "ttl" and not 1 <= int(value) <= 30:
            raise ValueError("ttl must be 1 to 30 minutes")
        parts.append("%s-%s" % (key, value))
    if params:
        raise ValueError("unknown parameters: %s" % ", ".join(sorted(params)))
    return "-".join(parts)


def proxy_url(username, password, socks=False):
    scheme, port = ("socks5h", 7778) if socks else ("http", 7777)
    return "%s://%s:%[email protected]:%d" % (
        scheme, quote(username, safe=""), quote(password, safe=""), port)


print(proxy_url(build_username("USERNAME", country="us", state="ny", city="new_york", session="job1", ttl=20), "p@ss:word"))

Wie bekomme ich bei jeder Anfrage eine neue IP mit httpx?

Schalte Keep-alive aus. httpx verwendet standardmäßig Verbindungs-Pooling und eine wiederverwendete Verbindung hält ihre Exit-IP. Mit max_keepalive_connections=0 öffnet jede Anfrage eine neue Verbindung zum Gateway und läuft meist über eine andere Residential-IP. num_bytes_downloaded zeigt die empfangenen Bytes auf der Leitung an, was der Verkehrsabrechnung am nächsten kommt.

httpx: rotierender Client
import httpx

PROXY = "http://USERNAME-country-gb:[email protected]:7777"

# No keep-alive: every request opens a new connection, so it usually gets a new exit IP
with httpx.Client(
    proxy=PROXY,
    timeout=httpx.Timeout(30.0, connect=10.0),
    limits=httpx.Limits(max_keepalive_connections=0),
    follow_redirects=True,
) as client:
    for _ in range(3):
        r = client.get("https://api.ipify.org")
        print(r.text, r.num_bytes_downloaded, "bytes on the wire")

Wie scrape ich nebenläufig mit asyncio, ohne eine Seite zu überlasten?

Beschränke die Nebenläufigkeit pro Host, nicht nur global. Ein globales Limit von 50 lässt alle 50 Anfragen dieselbe Seite treffen, wenn deine URL-Liste nach Domäne sortiert ist. Ein Semaphore pro Hostname hält jede Seite auf einem höflichen Level, während der Crawl insgesamt schnell bleibt. Starte mit 2 bis 4 pro Host und lies den Nebenläufigkeits-Guide, bevor du erhöhst.

httpx.AsyncClient mit Semaphore pro Host
import asyncio
from collections import defaultdict
from urllib.parse import urlsplit

import httpx

PROXY = "http://USERNAME-country-us:[email protected]:7777"
PER_HOST = 4  # parallel requests per target host
host_slots = defaultdict(lambda: asyncio.Semaphore(PER_HOST))


async def fetch(client, url):
    async with host_slots[urlsplit(url).hostname]:
        try:
            r = await client.get(url)
            return url, r.status_code, r.num_bytes_downloaded
        except httpx.HTTPError as exc:
            return url, type(exc).__name__, 0


async def main(urls):
    limits = httpx.Limits(max_connections=50, max_keepalive_connections=0)
    timeout = httpx.Timeout(30.0, connect=10.0)
    async with httpx.AsyncClient(proxy=PROXY, limits=limits, timeout=timeout) as client:
        for result in await asyncio.gather(*(fetch(client, u) for u in urls)):
            print(*result)


asyncio.run(main(["https://example.com/", "https://example.org/", "https://example.net/"]))

Wie verwende ich einen Proxy mit aiohttp?

Übergebe das Gateway als proxy= bei jeder Anfrage, mit den Zugangsdaten in der Proxy URL. Das funktioniert in jeder aiohttp 3.x Version ohne Warnungen; BasicAuth und der proxy_auth= Parameter sind seit aiohttp 3.14 veraltet und werden in 4.0 entfernt. Ein TCPConnector(force_close=True) schließt jede Verbindung nach der Antwort, sodass jede Anfrage meist einen neuen Exit bekommt. Ohne diesen schließt aiohttp Verbindungen nicht wieder und du hast für eine Weile dieselbe IP.

aiohttp mit Zugangsdaten in der Proxy URL
import asyncio

import aiohttp

# Credentials go in the proxy URL; percent-encode a password that contains @ or :
PROXY = "http://USERNAME-country-fr:[email protected]:7777"


async def main():
    # force_close=True: one connection per request, so each request usually gets a new exit IP
    connector = aiohttp.TCPConnector(limit=20, force_close=True)
    timeout = aiohttp.ClientTimeout(total=60, sock_connect=10)
    async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
        for _ in range(3):
            async with session.get("https://api.ipify.org", proxy=PROXY) as resp:
                print(resp.status, await resp.text())


asyncio.run(main())

Wie behalte ich eine IP für einen mehrstufigen Ablauf?

Erzeuge eine Session-ID pro Ablauf und füge sie mit einer längeren TTL als der Ablaufdauer im Benutzernamen ein. Keep-alive ist hier in Ordnung: Du willst ja denselben Exit. Wenn das Residential Gerät hinter der Session offline geht, kann die IP vor Ablauf der TTL wechseln, also mach den Ablauf restartbar vom letzten Checkpoint.

Sticky Session mit requests
import uuid

import requests

session_id = uuid.uuid4().hex[:10]  # one ID per flow, lowercase letters and digits
user = "USERNAME-country-us-state-ca-session-%s-ttl-20" % session_id
proxy = "http://%s:[email protected]:7777" % user

with requests.Session() as s:
    s.proxies = {"http": proxy, "https": proxy}
    first = s.get("https://api.ipify.org", timeout=(10, 30)).text
    second = s.get("https://api.ipify.org", timeout=(10, 30)).text
    print(first, second, "same exit" if first == second else "exit changed")

Wie viel Traffic verbraucht ein Python-Scraper pro Seite?

Miss es bei 100 realen Seiten, bevor du Volumen kaufst. Logge num_bytes_downloaded in httpx oder die Länge des komprimierten Bodys in deiner eigenen Middleware und multipliziere mit deiner Seitenanzahl. HTML-Anfragen kosten üblicherweise einige Zehntausend Bytes pro Seite; der Bandwidth Guide liefert Zahlen und Kosten pro 1.000 Seiten zu CrawlRelay Preisen.

Drei Gewohnheiten reduzieren den Traffic ohne Ergebnisänderung:

  • Sende Accept-Encoding: gzip, br (httpx und requests senden standardmäßig gzip), damit Seiten komprimiert übertragen werden.
  • Lade den JSON-Endpunkt, den eine Seite lädt, wenn die Seite das erlaubt oder dokumentiert, statt das volle HTML.
  • Überspringe unveränderte Seiten mit If-None-Match oder If-Modified-Since: ein 304 Not Modified kostet nur ein paar hundert Bytes.

Python und Residential-Proxys: Fragen

requests, httpx oder aiohttp: Was soll ich fürs Scraping nutzen?

Verwende requests für einfache Skripte und kleine Crawls. Nutze httpx, wenn du dieselbe API in synchronem und asynchronem Code willst, und HTTP/2 über httpx[http2]. Für sehr hohe Konkurrenzen im reinen asyncio nimm aiohttp. Für ein Crawl mit Scheduling, Duplikaterkennung und Pipelines nutze Scrapy statt diese Teile selbst zu programmieren.

Warum bekomme ich SSL: WRONG_VERSION_NUMBER mit meinem Proxy in Python?

Du hast wahrscheinlich https:// vor die Proxy-Adresse geschrieben. Der Gateway-Port 7777 spricht reines HTTP und öffnet einen CONNECT-Tunnel für HTTPS-Seiten, daher muss die Proxy-URL in den Schlüsseln http und https mit http:// beginnen. Siehe die Fehlerseite.

Wie nutze ich SOCKS5 Residential-Proxys in Python?

Installiere das Extra (pip install "requests[socks]" oder pip install "httpx[socks]"), dann verwende socks5h://USERNAME:[email protected]:7778. Der h sendet Hostnamen an den Proxy, sodass DNS am Exit aufgelöst wird und du die gleichen regionalen Antworten siehst wie lokale Besucher.

Warum gibt mein rotierender Residential-Proxy zweimal dieselbe IP zurück?

Dein Client hat eine wiederverwendete Keep-Alive-Verbindung genutzt, dabei rotiert der Proxy nur bei neuen Verbindungen. Sende Connection: close bei requests, setze max_keepalive_connections=0 in httpx oder nutze force_close=True in aiohttp. Prüfe außerdem, dass im Benutzernamen kein session--Teil vorhanden ist, denn der sorgt absichtlich dafür, dass eine IP bleibt.

Wie setze ich Timeouts für Anfragen über Residential-Proxys?

Setze sie explizit: requests hat standardmäßig kein Timeout. Ein Connect-Timeout von etwa 10 Sekunden und ein Read-Timeout von 30 Sekunden passen für HTML-Seiten; mobile 4G-Proxys und langsame Ziele benötigen 45 bis 60 Sekunden. Wiederhole einen Timeout einmal mit einer neuen Verbindung, anstatt länger zu warten. Siehe Read Timeouts.

Kann ich diese Residential- und mobile 4G-Proxys in Jupyter oder mit pandas nutzen?

Ja. Alles, was intern requests oder httpx verwendet, akzeptiert dieselben Proxy-Einstellungen. Für pandas.read_html oder read_csv einer URL lade den Inhalt zuerst mit einem durch Residential-Proxy geleiteten requests-Aufruf herunter, und übergib dann Text oder Bytes an pandas.

Führe deinen Python-Scraper durch Residential IPs aus

1,50 $ für 1 GB, 0,50 $/GB ab 50 GB.

Ab 0,50 $/GB · ohne KYC

Jetzt starten