# Rotujące proxy rezydencjalne w Pythonie: requests, httpx i aiohttp

> Rotujące proxy rezydencjalne w Pythonie: requests z ponownymi próbami, httpx synchroniczne i asynchroniczne, aiohttp, sesje trwałe i liczenie bajtów. Kod sprawdzony pod względem składni.

- URL: https://crawlrelay.com/pl/docs/python/
- Ostatnia aktualizacja: 2026-10-13
- Publisher: CrawlRelay (https://crawlrelay.com)

Wzorce produkcyjne, nie jednowierszowce: ponowne próby z uwzględnieniem Retry-After, nowe IP przy każdym żądaniu lub jedno IP na cały przepływ, konkurencja per host w asyncio oraz faktyczny koszt bajtów na stronę.

**Szybka odpowiedź — Jak korzystać z rotujących proxy rezydencjalnych w Pythonie?**

Podaj `http://USERNAME:PASSWORD@gw.crawlrelay.com:7777` jako proxy zarówno dla `http` jak i `https` w requests, jako `proxy=` w httpx 0.26+, lub jako `proxy=` na każde żądanie w aiohttp. **CrawlRelay** proxy rezydencjalne rotują przy każdym nowym połączeniu i pozostają trwałe dzięki `-session-<id>` w nazwie użytkownika. Kosztują 1,50 USD za 1 GB i 0,50 USD/GB od 50 GB. Płatność w kryptowalutach, bez KYC.

## Szybki przegląd konfiguracji Python

| Atrybut | Wartość |
| --- | --- |
| requests | `proxies={"http": url, "https": url}`; ponowne próby przez urllib3 `Retry` |
| httpx | `httpx.Client(proxy=url)`; stary argument `proxies=` usunięty w httpx 0.28 |
| aiohttp | `session.get(url, proxy="http://USER:PASS@host:port")`, dane uwierzytelniające w URL proxy |
| SOCKS5 | `pip install "requests[socks]"` lub `httpx[socks]`, potem `socks5h://` na porcie 7778 |
| Nowe IP przy każdym żądaniu | Wyłącz keep-alive: `Connection: close`, `max_keepalive_connections=0` lub `force_close=True` |
| To samo IP dla całego przepływu | `-session-<id>-ttl-<minutes>` w nazwie użytkownika, do 30 minut |
| Schemat URL proxy | Zawsze `http://` dla portu HTTP, nawet na stronach HTTPS |

## Jak używać proxy z requests z ponownymi próbami uwzględniającymi Retry-After?

Zainstaluj `HTTPAdapter` z retry urllib3 `Retry` na `Session`. Próbuje ponownie przy błędach połączenia i podanych statusach, czeka z wykładniczym opóźnieniem i respektuje nagłówek `Retry-After` wysyłany przez serwery przy 429 i 503. Ustaw `trust_env = False`, by zmienna `HTTPS_PROXY` nie nadpisywała twojego proxy.

*requests + retry urllib3*

```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)
```

## Jak bezpiecznie zbudować docelowe URL proxy?

Generuj nazwę użytkownika w jednej funkcji i ją waliduj. Literówka w kodzie kraju lub znak niezakodowany w haśle powodują błąd [407](https://crawlrelay.com/pl/docs/errors/407-proxy-authentication-required/) wyglądający jak problem z uwierzytelnianiem. Poniższy helper zachowuje udokumentowany porządek (`USERNAME-country-{cc}-state-{state}-city-{city}-zip-{zip}-asn-{asn}-session-{id}-ttl-{minutes}`), odrzuca nieznane klucze i koduje URL obu danych logowania.

*Generator nazwy użytkownika i URL proxy*

```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"))
```

## Jak uzyskać nowe IP przy każdym żądaniu w httpx?

Wyłącz keep-alive. httpx domyślnie korzysta z puli połączeń, a ponowne ich użycie utrzymuje to samo IP wyjściowe. Z `max_keepalive_connections=0` każde żądanie otwiera nowe połączenie do bramki i zwykle wychodzi innym mobile proxy 4G. `num_bytes_downloaded` pokazuje liczbę bajtów odebranych na łączu, co najbliżej odpowiada rozliczeniu transferu.

*httpx: rotujący klient*

```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")
```

## Jak równolegle robić scraping w asyncio, nie przeciążając jednej strony?

Ogranicz konkurencję **per host**, nie tylko globalnie. Globalny limit 50 sprawi, że wszystkie 50 żądań uderzy w ten sam serwis, gdy lista URL będzie posortowana po domenie. Semafor na hostname utrzymuje poziom grzeczności wobec każdego serwisu, a całość crawl pozostaje szybka. Zacznij od 2 do 4 na host i przeczytaj [przewodnik po konkurencji](https://crawlrelay.com/pl/docs/concurrency/) zanim zwiększysz limit.

*httpx.AsyncClient z semaforem per 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/"]))
```

## Jak korzystać z proxy w aiohttp?

Podaj bramkę jako `proxy=` dla każdego żądania, z danymi uwierzytelniającymi w URL proxy. Działa to na każdej wersji aiohttp 3.x bez ostrzeżeń; `BasicAuth` i parametr `proxy_auth=` są przestarzałe od aiohttp 3.14 i zostaną usunięte w wersji 4.0. `TCPConnector(force_close=True)` zamyka połączenie po odpowiedzi, więc każde żądanie ma zwykle nowe wyjście. Bez tego aiohttp ponownie wykorzystuje połączenia, utrzymując to samo IP na jakiś czas.

*aiohttp z danymi uwierzytelniającymi w URL proxy*

```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())
```

## Jak utrzymać jedno IP w wieloetapowym przepływie?

Wygeneruj jedną sesję na przepływ i umieść ją w nazwie użytkownika z TTL dłuższym niż przepływ. Keep-alive jest ok, chcesz to samo wyjście. Jeśli urządzenie proxy rezydencjalne przestanie działać, IP może się zmienić przed końcem TTL, więc zrób przepływ możliwy do wznowienia od ostatniego punktu kontrolnego.

*Sticky session z 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")
```

## Ile ruchu generuje scraper w Pythonie na stronę?

Zmierz na 100 prawdziwych stron zanim kupisz transfer. Loguj `num_bytes_downloaded` w httpx lub długość skompresowanego ciała w własnym middleware i pomnóż przez liczbę stron. Żądania tylko HTML zwykle kosztują dziesiątki kilobajtów na stronę; [przewodnik po transferze](https://crawlrelay.com/pl/guides/bandwidth-calculator/) podaje liczby i koszt na 1000 stron przy cenach CrawlRelay.

Trzy zwyczaje zmniejszają ruch bez utraty efektów:

- Wysyłaj `Accept-Encoding: gzip, br` (httpx i requests domyślnie wysyłają gzip), by strony płynęły skompresowane.
- Pobieraj punkt JSON, który strona ładuje, jeśli dokumentacja lub regulamin na to pozwala, zamiast całego HTML.
- Pomijaj niezmienione strony z `If-None-Match` albo `If-Modified-Since`: `304 Not Modified` kosztuje tylko kilkaset bajtów.

## Python i proxy: pytania

### requests, httpx czy aiohttp: którego użyć do scrapingu?

Używaj requests do prostych skryptów i małych crawlów. httpx sprawdzi się, gdy chcesz tę samą API w kodzie synchronicznym i asynchronicznym oraz HTTP/2 przez `httpx[http2]`. aiohttp to wybór przy bardzo dużej współbieżności w czystym asyncio. Przy crawl z harmonogramem, deduplikacją i pipeline'ami lepiej użyć [Scrapy](https://crawlrelay.com/pl/docs/scrapy/) zamiast pisać te elementy samodzielnie.

### Dlaczego dostaję błąd SSL: WRONG_VERSION_NUMBER z moim proxy w Pythonie?

Prawdopodobnie wpisałeś `https://` przed adresem proxy. Port bramki 7777 obsługuje zwykły HTTP i otwiera tunel CONNECT dla stron HTTPS, więc w URL proxy musi być `http://` w kluczach `http` i `https`. Zobacz [stronę błędu](https://crawlrelay.com/pl/docs/errors/ssl-wrong-version-number/).

### Jak używać mobilne proxy 4G SOCKS5 w Pythonie?

Zainstaluj dodatek (`pip install "requests[socks]"` lub `pip install "httpx[socks]"`), potem użyj `socks5h://USERNAME:PASSWORD@gw.crawlrelay.com:7778`. `h` wysyła nazwy hostów do proxy, więc rozwiązywanie DNS odbywa się na wyjściu i widzisz te same odpowiedzi regionalne, co lokalni użytkownicy.

### Dlaczego mój obracający się proxy rezydencjalne zwraca ten sam IP dwa razy?

Klient ponownie użył połączenia keep-alive, a rotacja odbywa się na nowe połączenie. W requests wyślij `Connection: close`, ustaw `max_keepalive_connections=0` w httpx lub użyj `force_close=True` w aiohttp. Sprawdź też, czy nazwa użytkownika nie zawiera `session-`, który celowo utrzymuje jeden IP.

### Jak ustawić timeouty dla zapytań przez proxy?

Ustaw je jawnie: requests domyślnie timeouta nie ma. Timeout na połączenie około 10 sekund i odczyt 30 sekund pasują do stron HTML; wyjścia mobilne i wolne cele potrzebują 45-60 sekund. Po timeout spróbuj ponownie na nowym połączeniu, zamiast czekać dłużej. Zobacz [read timeouts](https://crawlrelay.com/pl/docs/errors/read-timeout/).

### Czy mogę używać tych proxy w Jupyter lub z pandas?

Tak. Wszystko, co korzysta z requests lub httpx, przyjmie te same ustawienia proxy. Dla `pandas.read_html` lub `read_csv` w URL pobierz najpierw zawartość przez proxied requests, potem przekaż tekst lub bajty do pandas.

**Uruchom swój skraper Python przez proxy rezydencjalne** 1,50 USD za 1 GB, 0,50 USD/GB od 50 GB. [Zobacz ceny](https://crawlrelay.com/pl/pricing/) · [Poradnik Scrapy](https://crawlrelay.com/pl/docs/scrapy/)

---

CrawlRelay: CrawlRelay to serwis proxy rezydencjalne i mobilne proxy 4G/5G z rotacją, stworzony dla programistów i potoków danych AI: ruch bez wygasania w modelu pay-as-you-go od 0,50 USD/GB, płatny w kryptowalutach, bez konieczności przesyłania dokumentów. Bez KYC — brak dowodu, selfie i dokumentów. Płać w kryptowalutach.
