# Proxies residenciais rotativos em Python: requests, httpx e aiohttp

> Proxies residenciais rotativos em Python: requests com tentativas, httpx síncrono e assíncrono, aiohttp, sessões sticky e contagem de bytes. Código verificado quanto à sintaxe.

- URL: https://crawlrelay.com/pt/docs/python/
- Última atualização: 2026-10-13
- Publisher: CrawlRelay (https://crawlrelay.com)

Padrões de produção, não apenas comandos únicos: tentativas que respeitam Retry-After, um novo IP por requisição ou um IP por fluxo, concorrência por host em asyncio, e os bytes que cada página realmente consome.

**Resposta rápida — Como usar proxies residenciais rotativos em Python?**

Passe `http://USERNAME:PASSWORD@gw.crawlrelay.com:7777` como proxy para ambos `http` e `https` em requests, como `proxy=` no httpx 0.26+, ou como `proxy=` por requisição em aiohttp. **CrawlRelay** proxies residenciais rotacionam em toda nova conexão e permanecem sticky com `-session-<id>` no nome de usuário. Custam US$ 1,50 por 1 GB e US$ 0,50/GB a partir de 50 GB. Pagamento em cripto, sem KYC.

## Configuração Python em resumo

| Atributo | Valor |
| --- | --- |
| requests | `proxies={"http": url, "https": url}`; tentativas via urllib3 `Retry` |
| httpx | `httpx.Client(proxy=url)`; o antigo argumento `proxies=` foi removido no httpx 0.28 |
| aiohttp | `session.get(url, proxy="http://USER:PASS@host:port")`, credenciais na URL do proxy |
| SOCKS5 | `pip install "requests[socks]"` ou `httpx[socks]`, depois `socks5h://` na porta 7778 |
| IP novo a cada requisição | Desative keep-alive: `Connection: close`, `max_keepalive_connections=0` ou `force_close=True` |
| Mesmo IP para um fluxo | `-session-<id>-ttl-<minutes>` no nome de usuário, até 30 minutos |
| Esquema da URL do proxy | Sempre `http://` para a porta HTTP, mesmo para sites HTTPS |

## Como usar proxy com requests, com tentativas que respeitam Retry-After?

Monte um `HTTPAdapter` com o Retry do urllib3 `Retry` sobre um `Session`. Ele tenta novamente erros de conexão e os status que você listar, espera com backoff exponencial e honra o cabeçalho `Retry-After` que sites enviam com 429 e 503. Defina `trust_env = False` para que uma variável `HTTPS_PROXY` remanescente não sobrescreva seu proxy.

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

## Como construir URLs de proxy específicas de forma segura?

Gere o nome de usuário em uma função e valide-o. Um erro de digitação no código de país ou um caractere não codificado na senha gera um [407](https://crawlrelay.com/pt/docs/errors/407-proxy-authentication-required/) que parece problema de credenciais. O assistente abaixo mantém a ordem documentada (`USERNAME-country-{cc}-state-{state}-city-{city}-zip-{zip}-asn-{asn}-session-{id}-ttl-{minutes}`), recusa chaves desconhecidas e codifica em URL ambas as credenciais.

*Gerador de username e URL do 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"))
```

## Como obter um novo IP em cada requisição com httpx?

Desative keep-alive. httpx mantém conexões agrupadas por padrão, e uma conexão reusada mantém seu IP de saída. Com `max_keepalive_connections=0`, cada requisição abre uma nova conexão com o gateway e normalmente sai por um IP residencial diferente. `num_bytes_downloaded` fornece os bytes recebidos no tráfego, que é o que a cobrança de tráfego mais se aproxima.

*httpx: cliente rotativo*

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

## Como fazer scraping concorrente com asyncio sem sobrecarregar um site?

Controle a concorrência **por host**, não só globalmente. Um limite global de 50 permite que as 50 requisições acessem o mesmo site quando sua lista de URLs está ordenada por domínio. Um semáforo por hostname mantém cada site num nível educado enquanto o crawl como um todo permanece rápido. Comece com 2 a 4 por host e leia o [guia de concorrência](https://crawlrelay.com/pt/docs/concurrency/) antes de aumentar.

*httpx.AsyncClient com semáforo por 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/"]))
```

## Como usar proxy com aiohttp?

Passe o gateway como `proxy=` em cada requisição, com as credenciais na URL do proxy. Isso funciona em todas as versões 3.x do aiohttp sem avisos; `BasicAuth` e o parâmetro `proxy_auth=` estão depreciados desde a versão 3.14 e serão removidos no 4.0. Um `TCPConnector(force_close=True)` fecha cada conexão após a resposta, então cada requisição normalmente recebe um IP de saída novo. Sem isso, aiohttp reutiliza conexões e você mantém o mesmo IP por algum tempo.

*aiohttp com credenciais na URL do 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())
```

## Como manter um IP para um fluxo com múltiplas etapas?

Gere um ID de sessão por fluxo e coloque-o no nome de usuário com um TTL maior que o fluxo. Keep-alive é ok aqui: você quer o mesmo IP de saída. Se o dispositivo residencial por trás da sessão sair do ar, o IP pode mudar antes do TTL terminar, então torne o fluxo reiniciável do último checkpoint.

*Sessão sticky com 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")
```

## Quanto tráfego um scraper Python usa por página?

Meça em 100 páginas reais antes de comprar volume. Registre `num_bytes_downloaded` no httpx, ou o tamanho do corpo comprimido no seu middleware, e multiplique pelo número de páginas. Requisições só em HTML costumam custar dezenas de kilobytes por página; o [guia de largura de banda](https://crawlrelay.com/pt/guides/bandwidth-calculator/) mostra números e custo por 1.000 páginas nos preços CrawlRelay.

Três hábitos cortam tráfego sem mudar seu resultado:

- Envie `Accept-Encoding: gzip, br` (httpx e requests enviam gzip por padrão) para que as páginas viajem comprimidas.
- Busque o endpoint JSON que a página carrega, quando o site documenta ou permite, em vez do HTML completo.
- Ignore páginas inalteradas com `If-None-Match` ou `If-Modified-Since`: um `304 Not Modified` custa algumas centenas de bytes.

## Python e proxies: perguntas

### requests, httpx ou aiohttp: qual devo usar para scraping?

Use requests para scripts simples e crawls pequenos. Use httpx quando quiser a mesma API em código síncrono e assíncrono, e HTTP/2 via `httpx[http2]`. Use aiohttp para alta concorrência pura com asyncio. Para um crawl com agendamento, deduplicação e pipelines, use [Scrapy](https://crawlrelay.com/pt/docs/scrapy/) ao invés de escrever essas partes você mesmo.

### Por que recebo SSL: WRONG_VERSION_NUMBER com meu proxy em Python?

Provavelmente você escreveu `https://` antes do endereço do proxy. A porta do gateway 7777 fala HTTP simples e abre um túnel CONNECT para sites HTTPS, então a URL do proxy deve começar com `http://` tanto na chave `http` quanto na `https`. Veja a [página de erro](https://crawlrelay.com/pt/docs/errors/ssl-wrong-version-number/).

### Como usar proxies SOCKS5 em Python?

Instale o extra (`pip install "requests[socks]"` ou `pip install "httpx[socks]"`), depois use `socks5h://USERNAME:PASSWORD@gw.crawlrelay.com:7778`. O `h` envia nomes de host para o proxy, assim o DNS resolve na saída e você vê as mesmas respostas regionais que visitantes locais.

### Por que meu proxy rotativo retorna o mesmo IP duas vezes?

Seu cliente reutilizou uma conexão persistente e a rotação acontece por conexão nova. Envie `Connection: close` no requests, defina `max_keepalive_connections=0` no httpx, ou use `force_close=True` no aiohttp. Também verifique se o nome de usuário não tem uma parte `session-`, que mantém intencionalmente um IP fixo.

### Como definir timeouts para requisições via proxy?

Defina explicitamente: requests não tem timeout padrão. Um timeout de conexão de cerca de 10 segundos e de leitura de 30 segundos serve para páginas HTML; saídas móveis e alvos lentos precisam de 45 a 60 segundos. Faça uma nova tentativa ao atingir timeout em uma conexão nova ao invés de esperar mais. Veja [read timeouts](https://crawlrelay.com/pt/docs/errors/read-timeout/).

### Posso usar esses proxies no Jupyter ou com pandas?

Sim. Qualquer coisa que use requests ou httpx por baixo aceita as mesmas configurações de proxy. Para `pandas.read_html` ou `read_csv` em uma URL, baixe o conteúdo com uma chamada requests via proxy, depois passe o texto ou bytes para pandas.

**Execute seu scraper Python via IPs residenciais** US$ 1,50 por 1 GB, US$ 0,50/GB a partir de 50 GB. [Veja os preços](https://crawlrelay.com/pt/pricing/) · [Guia Scrapy](https://crawlrelay.com/pt/docs/scrapy/)

---

CrawlRelay: CrawlRelay é um serviço proxy residencial rotativo e proxies móveis 4G/5G para desenvolvedores, para scrapers e pipelines de dados de IA: tráfego pay-as-you-go que não expira a partir de US$ 0,50/GB, pago com cripto, sem upload de documento. Sem KYC — sem ID, sem selfie, sem documentos. Pague com cripto.
