Toda biblioteca HTTP em Python aceita um proxy como uma URL no formato scheme://user:pass@host:port; o que muda é o nome do parâmetro, se é definido por cliente ou por requisição, e como SOCKS5 e DNS são tratados. Os exemplos abaixo são o código exato que funciona com as versões atuais de requests, httpx e aiohttp — cada um foi executado através de um proxy com autenticação antes da publicação deste artigo — seguidos pelas três coisas que respondem pela maioria das perguntas do tipo “meu proxy não funciona em Python”: nomes de parâmetros errados copiados de tutoriais antigos, extras SOCKS ausentes e uma impressão digital TLS que denuncia o script independentemente do IP.

A URL do proxy

http://user:pass@proxy.example.com:8080     # Proxy HTTP, usado tanto para alvos http:// quanto https://
socks5://user:pass@proxy.example.com:1080   # SOCKS5, DNS resolvido localmente
socks5h://user:pass@proxy.example.com:1080  # SOCKS5, DNS resolvido pelo proxy (use este)

Dois pontos que confundem as pessoas. Primeiro, um proxy HTTP também lida com alvos HTTPS — o cliente envia CONNECT e tunela TLS através dele — então você quase nunca precisa de um esquema de proxy https://; isso significaria TLS para o próprio proxy, o que poucos provedores oferecem. Segundo, se seu nome de usuário contém parâmetros de rotação (user-country-de-session-abc123) ou sua senha contém @, : ou /, codifique-os em percentual (urllib.parse.quote(pw, safe='')) ou a URL será analisada incorretamente.

requests

import requests

PROXY = "http://user:pass@proxy.example.com:8080"
proxies = {"http": PROXY, "https": PROXY}

# Por requisição
r = requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=20)
print(r.json())

# Por sessão (reutiliza conexões; a forma normal)
s = requests.Session()
s.proxies.update(proxies)
r = s.get("https://api.ipify.org?format=json", timeout=20)

O dicionário é indexado pelo esquema do alvo: requisições para URLs http:// usam a entrada "http", requisições para URLs https:// usam "https". Defina ambos para o mesmo proxy, a menos que tenha um motivo para não fazer isso. Sempre passe um timeout; um proxy travado pode travar seu script para sempre.

SOCKS5 precisa do extra: pip install "requests[socks]". Então proxies = {"http": "socks5h://…", "https": "socks5h://…"}. Sem o extra, você recebe InvalidSchema: Missing dependencies for SOCKS support.

Variáveis de ambiente: requests honra HTTP_PROXY / HTTPS_PROXY / NO_PROXY por padrão (trust_env=True). Se um proxy está misteriosamente em uso quando você não definiu um, ou não está em uso quando você definiu, verifique o ambiente.

httpx

import httpx

PROXY = "http://user:pass@proxy.example.com:8080"

# Síncrono
with httpx.Client(proxy=PROXY, timeout=20) as client:
    r = client.get("https://api.ipify.org?format=json")
    print(r.json())

# Assíncrono
import asyncio
async def main():
    async with httpx.AsyncClient(proxy=PROXY, timeout=20) as client:
        r = await client.get("https://api.ipify.org?format=json")
        print(r.json())
asyncio.run(main())

O parâmetro é proxy= (singular). Tutoriais antigos mostram proxies={"http://": …, "https://": …}; essa palavra-chave foi depreciada no httpx 0.26 e removida no 0.28, e passá-la agora levanta TypeError: Client.__init__() got an unexpected keyword argument 'proxies'. Se você precisa de proxies diferentes para alvos diferentes, use mounts:

mounts = {
    "https://api.example.com": httpx.HTTPTransport(proxy="http://user:pass@dc-proxy:8080"),
    "all://": httpx.HTTPTransport(proxy="http://user:pass@resi-proxy:8080"),
}
client = httpx.Client(mounts=mounts)

SOCKS5: pip install "httpx[socks]", então proxy="socks5://…". httpx resolve nomes de host através do proxy SOCKS por padrão. HTTP/2: pip install "httpx[http2]" e httpx.Client(http2=True, …) — relevante porque um navegador via proxy já está em HTTP/2 (veja HTTP/2 e HTTP/3 através de proxies).

aiohttp

import aiohttp, asyncio

PROXY = "http://user:pass@proxy.example.com:8080"

async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.ipify.org?format=json",
                               proxy=PROXY,
                               timeout=aiohttp.ClientTimeout(total=20)) as r:
            print(await r.json())

asyncio.run(main())

O proxy é passado por requisição (ou definido uma vez via um conector personalizado). As credenciais vão na URL; a forma separada proxy_auth=aiohttp.BasicAuth(...) ainda funciona no 3.x, mas está depreciada a partir do 3.14 e programada para remoção no 4.0, então prefira a forma com URL. aiohttp não lê variáveis de ambiente HTTP_PROXY a menos que você crie a sessão com trust_env=True. O aiohttp nativo fala apenas proxies HTTP; para SOCKS use o pacote aiohttp-socks e seu ProxyConnector.

Rotacionando proxies: o padrão de session-ID

Com um gateway de backconnect (veja como funcionam os gateways de rotação) você raramente rotaciona em Python — você rotaciona mudando o nome de usuário. Um novo session ID significa um novo IP de saída; um reutilizado o mantém:

import secrets, requests

def proxy_for(session_id: str, country: str = "de") -> dict:
    user = f"customer-country-{country}-session-{session_id}"   # formato específico do provedor
    url  = f"http://{user}:PASSWORD@gate.provider.com:7777"
    return {"http": url, "https": url}

# Sticky: mesmo IP para um fluxo de várias etapas
sid = secrets.token_hex(4)
s = requests.Session(); s.proxies.update(proxy_for(sid))
s.get("https://shop.example/login"); s.post("https://shop.example/cart", data=...)

# Rotacionando: novo IP por item
for url in urls:
    requests.get(url, proxies=proxy_for(secrets.token_hex(4)), timeout=20)

Rotacione também em caso de falha: capture 403/429 e um marcador de CAPTCHA, e tente novamente com um session ID novo e um novo cookie jar — o mesmo IP com os mesmos cookies é o mesmo visitante.

O erro que nenhum proxy corrige: impressão digital TLS

Todas as três bibliotecas fazem conexões TLS através do módulo ssl do Python (OpenSSL). Sistemas anti-bot identificam esse handshake e sabem que não é um navegador, independentemente de como você define o User-Agent. Atrás de um IP residencial perfeito, o script ainda é identificado como script — o mecanismo está em impressão digital TLS explicada. Para alvos protegidos, mude para um cliente que imita navegador; curl_cffi mantém uma API semelhante à do requests:

# pip install curl_cffi
from curl_cffi import requests as cffi_requests

r = cffi_requests.get("https://protected.example/",
                      impersonate="chrome",                 # reproduz a impressão digital TLS + HTTP/2 do Chrome
                      proxies={"https": "http://user:pass@proxy.example.com:8080"},
                      timeout=20)

Então mantenha o resto da história consistente — um User-Agent do Chrome, client hints sec-ch-ua correspondentes, Accept-Language plausível para o país do proxy. Para sites que adicionalmente exigem desafios JavaScript, nenhum cliente HTTP é suficiente; use um navegador real como em Proxies em Playwright, Puppeteer e Selenium.

Erros e o que significam

Você vêSignificaCorreção
ProxyError … 407 Proxy Authentication RequiredCredenciais erradas, ou seu IP não está na lista de permissõesVerifique usuário/senha (strings de rotação longas!), codifique caracteres especiais, verifique a lista de permissões
InvalidSchema: Missing dependencies for SOCKS supportrequests sem o extra sockspip install "requests[socks]"
TypeError: … unexpected keyword argument 'proxies'httpx ≥ 0.28 com o parâmetro removidoUse proxy= ou mounts=
ProxyError … Cannot connect to proxy / ConnectTimeoutHost/porta errados, proxy fora do ar ou firewallVerifique com curl -x; tente o outro protocolo
IP real retornado por um endpoint de eco de IPProxy não aplicado (chave de dicionário errada, variável de ambiente sobrescrevendo, parâmetro por requisição ausente no aiohttp)Imprima session.proxies; verifique trust_env; passe proxy= na requisição
SSLError apenas através do proxyProxy está interceptando TLS (MITM) ou esquema erradoUse esquema http:// para o proxy; pergunte ao provedor se eles terminam TLS
403/CAPTCHA em sites protegidos, IP parece okImpressão digital TLS/HTTP identifica Pythoncurl_cffi com impersonate, ou um navegador real
Funciona por um tempo, depois 429Limite de taxa por IP atingidoRotacione o session ID; diminua a velocidade; veja o guia de rotação

Um modelo mínimo e correto

import requests, secrets
from urllib.parse import quote

GATE, PORT = "gate.provider.com", 7777
USER_BASE, PASS = "customer-country-de", quote("p@ss:word", safe="")

def make_session() -> requests.Session:
    sid = secrets.token_hex(4)
    url = f"http://{USER_BASE}-session-{sid}:{PASS}@{GATE}:{PORT}"
    s = requests.Session()
    s.proxies.update({"http": url, "https": url})
    s.headers.update({"User-Agent": "python-requests"})   # UA honesto para alvos tolerantes
    return s

s = make_session()
r = s.get("https://api.ipify.org?format=json", timeout=20)
r.raise_for_status()
print(r.json())

Verifique se o IP muda e então construa em cima disso. Para um pré-voo completo (vazamentos, cabeçalhos, listas de bloqueio) veja Como testar um proxy; para escolher entre datacenter e residencial para um determinado alvo, a comparação de tipos de proxy.

Perguntas frequentes

Como usar um proxy com Python requests?

Passe proxies={"http": url, "https": url} para a requisição ou defina em uma Session, onde url é http://user:pass@host:port. Adicione timeout=. Para SOCKS5 instale requests[socks] e use socks5h://.

Por que o httpx diz ‘unexpected keyword argument proxies’?

Porque proxies= foi removido no httpx 0.28. Use proxy="http://…" para um proxy, ou mounts= para proxies por alvo.

Como definir um proxy no aiohttp?

Passe proxy="http://user:pass@host:port" para cada requisição (session.get(url, proxy=…)). O parâmetro proxy_auth= está depreciado; coloque as credenciais na URL. Use aiohttp-socks para SOCKS.

Como rotacionar proxies em Python?

Com um provedor de backconnect, mude o session ID no nome de usuário do proxy por requisição ou por fluxo — sem necessidade de lista de IPs. Rotacione em 403/429 e associe cada novo IP a um cookie jar novo.

Por que meu script é bloqueado quando meu navegador no mesmo proxy não é?

Impressão digital TLS e HTTP/2: o módulo ssl do Python não parece um navegador. Use curl_cffi com impersonate= ou automatize um navegador real.

Devo usar socks5 ou socks5h?

socks5h. O h faz o proxy resolver nomes de host, prevenindo vazamentos de DNS e permitindo alcançar hosts que apenas o proxy pode resolver.