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

> Rotierende Residential-Proxys in Python: requests mit Wiederholungen, httpx synchron und asynchron, aiohttp, Sticky Sessions und Byte-Anzahlen. Syntax-geprüfter Code.

- URL: https://crawlrelay.com/de/docs/python/
- Zuletzt aktualisiert: 2026-10-13
- Publisher: CrawlRelay (https://crawlrelay.com)

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.

**Kurze Antwort — Wie verwende ich rotierende Residential-Proxys in Python?**

Übergebe `http://USERNAME:PASSWORD@gw.crawlrelay.com: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

| Attribut | Wert |
| --- | --- |
| requests | `proxies={"http": url, "https": url}`; Wiederholungen über urllib3 `Retry` |
| httpx | `httpx.Client(proxy=url)`; das alte `proxies=` Argument wurde in httpx 0.28 entfernt |
| aiohttp | `session.get(url, proxy="http://USER:PASS@host:port")`, Zugangsdaten in der Proxy-URL |
| SOCKS5 | `pip install "requests[socks]"` oder `httpx[socks]`, dann `socks5h://` auf Port 7778 |
| Neue IP pro Anfrage | Keep-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 Schema | Immer `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*

```python
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:%s@gw.crawlrelay.com: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](https://crawlrelay.com/de/docs/errors/407-proxy-authentication-required/), 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*

```python
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:%s@gw.crawlrelay.com:%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*

```python
import httpx

PROXY = "http://USERNAME-country-gb:PASSWORD@gw.crawlrelay.com: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](https://crawlrelay.com/de/docs/concurrency/), bevor du erhöhst.

*httpx.AsyncClient mit Semaphore pro Host*

```python
import asyncio
from collections import defaultdict
from urllib.parse import urlsplit

import httpx

PROXY = "http://USERNAME-country-us:PASSWORD@gw.crawlrelay.com: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*

```python
import asyncio

import aiohttp

# Credentials go in the proxy URL; percent-encode a password that contains @ or :
PROXY = "http://USERNAME-country-fr:PASSWORD@gw.crawlrelay.com: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*

```python
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:PASSWORD@gw.crawlrelay.com: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](https://crawlrelay.com/de/guides/bandwidth-calculator/) 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](https://crawlrelay.com/de/docs/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](https://crawlrelay.com/de/docs/errors/ssl-wrong-version-number/).

### Wie nutze ich SOCKS5 Residential-Proxys in Python?

Installiere das Extra (`pip install "requests[socks]"` oder `pip install "httpx[socks]"`), dann verwende `socks5h://USERNAME:PASSWORD@gw.crawlrelay.com: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](https://crawlrelay.com/de/docs/errors/read-timeout/).

### 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. [Preise ansehen](https://crawlrelay.com/de/pricing/) · [Scrapy Anleitung](https://crawlrelay.com/de/docs/scrapy/)

---

CrawlRelay: CrawlRelay ist ein entwicklerfreundlicher rotierender Residential-Proxy- und 4G/5G mobile Proxy-Service für Scraper und KI-Datenpipelines: nicht verfallende Pay-as-you-go-Traffic ab 0,50 $/GB, mit Krypto bezahlt, ohne ID-Upload. Kein KYC — keine ID, kein Selfie, keine Dokumente. Mit Krypto bezahlen.
