Proxy no Python requests: configuração, autenticação e erros
Como configurar proxy no Python Requests, autenticar sem vazar senha, separar HTTP de CONNECT, tratar timeout, TLS e 407, e conferir SOCKS5 versus socks5h.
Este texto é para quem precisa mandar o Python Requests por um proxy e conferir o caminho. Os trechos usam dados dummy.
01Configurar um proxy no requests e confirmar o caminho
Os exemplos seguem a documentação oficial de proxies do Requests, conferida em 14 de outubro de 2026. O laboratório local usou Python 3.14.6, Requests 2.34.2, urllib3 2.8.0 e PySocks 1.7.1, com verificação TLS ligada. Ele mostra protocolo. Não mede velocidade, geografia nem qualidade de um IP de provedor.
Cada método aceita um dicionário proxies. As chaves são o esquema da URL de destino. Os valores são a URL do proxy:
import requests
proxies = {
"http": "http://203.0.113.10:8080",
"https": "http://203.0.113.10:8080",
}
session = requests.Session()
session.trust_env = False
r = session.get("https://example.com/", proxies=proxies, timeout=(3.05, 27))
print(r.status_code)
- Crie uma
Sessione definatrust_env = Falseenquanto você escolhe o proxy no código. - Aponte HTTP e HTTPS para o mesmo proxy se o provedor oferece um proxy HTTP com CONNECT.
- Passe sempre uma tupla de timeout. Sem isso a chamada pode ficar presa.
- Faça um GET pequeno contra um endpoint que você controla.
- Leia a resposta e o log do proxy. A página Qual é o meu IP no navegador mede a saída do navegador, não a rota do Python.
No laboratório, o GET direto no origin local devolveu HTTP 200. O mesmo GET pelo proxy aberto em loopback também 200. O proxy viu a forma absoluta GET http://127.0.0.1:53653/ HTTP/1.1. Sem esse rastro você só sabe que alguma coisa respondeu 200.
Requests 2.34.2 aceitou 127.0.0.1:8080 sem esquema. A chamada passou com HTTP 200. Por dentro, prepend_scheme_if_needed completa http://. Escreva o esquema mesmo assim. Sem http:// ou socks5:// a URL fica ambígua quando SOCKS entra no jogo. A documentação estável diz que a URL do proxy precisa incluir o esquema. Inferir HTTP não torna o valor sem esquema uma forma portátil.
Uma chave no formato https://api.interna.exemplo vale só para aquele host, não para subdomínios.
02Separar o proxy HTTP do destino HTTPS
A chave "https" quase sempre aponta para uma URL de proxy http://. Isso é proposital. O urllib3 documenta o túnel: destino HTTP vai em forma absoluta, destino HTTPS vira CONNECT e o TLS nasce depois, no túnel. No laboratório o evento do proxy foi CONNECT localhost:53654 HTTP/1.1 enquanto a URL alvo era https://localhost:53654/. O esquema do destino não é o esquema do endpoint do proxy.

https:// na URL do proxy só entra quando o provedor termina TLS na própria porta do proxy. Isso é outro serviço, não o forward proxy clássico.
A mesma senha ausente não se parece nos dois caminhos:
| Sintoma no Requests 2.34.2 | Camada | O que conferir |
|---|---|---|
| Status 407, corpo "Proxy Authentication Required", sem exception | Proxy HTTP, GET em forma absoluta | Usuário, senha, percent-encoding. Não é falha de Python. |
ProxyError com Tunnel connection failed: 407 | CONNECT para destino HTTPS | A mesma senha, agora no túnel. HTTPProxyAuth não bastou aqui. |
| Status 401 depois do login válido no proxy | Servidor de destino | O proxy passou. A aplicação no origin recusou. |
ProxyError com ConnectTimeoutError | TCP até o proxy | Host, porta, firewall. O timeout é o connect, não o relógio inteiro da chamada. |
ConnectionError com ReadTimeoutError na cadeia | Leitura depois do connect | O corpo atrasou. Não use um único número como prazo total. |
SSLError / CERTIFICATE_VERIFY_FAILED | TLS no destino, dentro do túnel | CA do destino ou de um proxy que intercepta. Não desligue verify. |
ConnectionError, nodename nor servname provided em socks5:// | DNS no cliente | Hostname sem resolução local. socks5h:// manda o nome ao proxy. |
Se você só quer saber se um endpoint responde, o checador de proxy basta para um teste manual. Ele não substitui o rastro do Python. Protocolo não é origem do IP. Um GET 200 não prova anonimato, país, elegibilidade de conta nem acesso universal ao alvo.
03Passar usuário e senha sem expor credenciais
A documentação pede Basic Auth na URL do proxy, com percent-encoding por componente. Caractere especial na senha não entra cru na URL:
from urllib.parse import quote
user = quote("demo", safe="")
password = quote("p@ss:/#%", safe="")
proxies = {
"http": f"http://{user}:{password}@203.0.113.10:8080",
"https": f"http://{user}:{password}@203.0.113.10:8080",
}
Sem login, o proxy de autenticação local devolveu 407 como resposta normal no GET HTTP. O mesmo header ausente no HTTPS virou requests.exceptions.ProxyError com OSError('Tunnel connection failed: 407 Proxy Authentication Required'). Os dois 407 não são o mesmo objeto. Uma página genérica de diagnóstico 407 no navegador é outro assunto.
Com os dados dummy já codificados na URL, HTTP e CONNECT HTTPS chegaram a 200 depois que a CA de laboratório foi passada em verify. Senha errada no GET HTTP também ficou em 407, sem exception.
A RFC 7617, seção 2 é clara: o primeiro dois-pontos separa user-id e senha. User-id com dois-pontos é inválido depois da decodificação. Senha pode ter dois-pontos. No laboratório, demo%3Ax na parte de usuário ainda virou 407, porque o decode reconstitui o dois-pontos e o Basic quebra no lugar errado.
HTTPProxyAuth funcionou no GET em forma absoluta (200). No CONNECT, a mesma classe não carregou o header no túnel: de novo ProxyError com 407. Coloque usuário e senha na URL do proxy, já codificados, quando o alvo for HTTPS.

Não grave senha em variável de ambiente compartilhada nem em repositório. O Requests avisa isso na página de proxies. Logs e figuras deste artigo redigem a senha dummy.
Retries ilimitados para furar 407 não cabem aqui. Tentativa limitada, depois pare e leia o status.
04Entender Session, variáveis de ambiente e trustenv
A documentação estável alerta: session.proxies pode ser sobrescrito pelos proxies do ambiente, os que urllib.request.getproxies devolve. Para mandar de verdade, passe proxies= em cada chamada ou desligue o ambiente.
No processo normal, HTTP_PROXY e HTTPS_PROXY em maiúsculas foram lidas. O GET HTTP saiu pelo proxy aberto. O mesmo processo com session.proxies apontando para um endereço morto ainda usou o ambiente. A chamada por request com proxies={"http": None, "https": None} ignorou o ambiente e foi direto ao origin, 200.
Session.trust_env = False ignorou HTTP_PROXY e HTTPS_PROXY. Também ignorou REQUESTS_CA_BUNDLE. Com trust_env = True, o mesmo bundle fez o HTTPS local passar. Com False, o default verify=True caiu em SSLError / unable to get local issuer certificate. O efeito da CA de ambiente some junto com o proxy de ambiente. Não é um interruptor só de proxy.
CPython 3.14.6, em urllib.request.getproxies_environment, descarta HTTP_PROXY quando REQUEST_METHOD está definido. É o CVE-2016-1000110, o caso CGI. No laboratório, com REQUEST_METHOD=GET e HTTP_PROXY preenchido, getproxies() voltou {}. Isso não é a regra do curl, que trata http_proxy minúsculo de outro jeito. Não misture as duas histórias.
Prepared requests também não herdam o ambiente sozinhas. A documentação de Session pede merge_environment_settings se você montar o PreparedRequest na mão. Fora desse fluxo, trust_env=False e proxies= explícito deixam o teste reproduzível.
05Testar SOCKS5, socks5h e a resolução DNS
SOCKS não vem no Requests puro. A página oficial pede python -m pip install 'requests[socks]', que puxa PySocks 1.7.1. Sem isso a URL socks5:// nem sobe.
proxies = {
"http": "socks5h://127.0.0.1:1080",
"https": "socks5h://127.0.0.1:1080",
}
socks5:// resolve o DNS no cliente. socks5h:// manda o hostname ao proxy, no mesmo espírito do curl. Chute a partir de um 200 não prova onde o nome foi resolvido. Precisa de hostname controlado e rastro no proxy.
O laboratório usou lab-origin.invalid, nome que o resolver local não conhece, mapeado só no fixture SOCKS para 127.0.0.1. Com socks5:// o cliente falhou antes de falar com o proxy: ConnectionError / NewConnectionError / gaierror, [Errno 8] nodename nor servname provided, or not known. Zero eventos SOCKS. Com socks5h:// o proxy registrou ATYP 3 e addr=lab-origin.invalid, e o GET voltou 200. Um GET socks5:// para 127.0.0.1 mostrou ATYP 1, IPv4, porque o cliente já tinha o endereço.

06Diagnosticar timeout, TLS e autenticação
O quickstart de timeouts diz que o parâmetro não é limite do download inteiro. É espera sem bytes no socket. Sem timeout, a chamada não expira.
A tupla (connect, read) separa as duas esperas. (3.05, 10) não é um orçamento de 13 segundos. Connect curto contra 192.0.2.1 gerou ConnectTimeout com connect timeout=0.4. Pelo proxy morto no mesmo prefixo, a classe visível foi ProxyError com ConnectTimeoutError na cadeia. O connect falhou no proxy, não no origin.
Corpo atrasado depois dos headers: o origin local dormiu 3 segundos no body. Com timeout=(3.05, 0.4) o Requests 2.34.2 não levantou ReadTimeout puro. Levantou ConnectionError cujo texto é Read timed out. e a cadeia traz ReadTimeoutError. Trate a cadeia, não só o nome da exception de fora.
TLS: sem a CA de laboratório, verify=True (default) falhou com SSLCertVerificationError / unable to get local issuer certificate. Com verify no PEM público da CA, o mesmo origin HTTPS respondeu 200. Não use verify=False no código de produção. Proxy que intercepta TLS pede a CA desse proxy, não um atalho.
urllib3.util.retry.Retry com total=3 e status_forcelist=(503,). allowed_methods default é GET, HEAD, OPTIONS, PUT, DELETE, TRACE.
| Método | Resposta do origin | Batidas no origin | Espera |
|---|---|---|---|
| GET | 503 com Retry-After: 1 | 4 (pedido mais 3 retries) | 3,023 s |
| POST | 503 | 1 (uma vez só) | 0,002 s |
Os 3,023 s do GET não são teto de relógio de 3 segundos. Erro de connect ainda pode retentar POST, porque _is_connection_error não consulta o método. Read e status de POST, não. Ligue replay só em operação segura.
401 no origin depois de proxy autenticado continuou 401. Não confunda com 407.

07Escolher um endpoint compatível e conferir o resultado
Antes de comprar IP, decida o protocolo que o cliente fala. Requests fala HTTP proxy com CONNECT e, com o extra SOCKS, socks5 / socks5h. Residencial ou datacenter é outra pergunta. A comparação de origem está em proxies residenciais vs. datacenter. Catálogo em proxies residenciais e proxies móveis. Nenhum desses links prova que o seu script Python saiu por aquele IP.
Confira o endpoint no checador se quiser um teste manual. Depois, no código:
trust_env = Falseno teste.- URL de proxy com esquema explícito.
- Usuário e senha com
quote(..., safe="")por componente. - Timeout em tupla.
verifycom a CA certa se houver interceptação.- Log do proxy: GET absoluto versus CONNECT, ATYP 1 versus 3 no SOCKS.
As fichas abaixo estão publicadas em português neste catálogo e citam HTTP ou SOCKS5. Não passaram por este laboratório. Não são prova de sucesso em produção, geolocalização ou conta.

A SOAX vende proxies residenciais e móveis rotativos num pool compartilhado de créditos, com datacenter e ISP nos mesmos planos. O Builder começa em $200/mês + IVA (200 créditos); o tráfego Tier 1 é $3/GB no Builder.

A Bright Data é uma grande rede de proxies para coleta de dados: IPs residenciais, móveis, ISP e de datacenter em cerca de 195 países. O tráfego residencial pode ser pago por uso, sem assinatura, e os endereços de datacenter e ISP são vendidos em pacotes a partir de 10 IPs. O acesso residencial e móvel exige verificação de identidade.

A Oxylabs vende proxies residenciais, móveis, ISP e de datacenter em uma única assinatura mensal a partir de US$ 30. Pagamento: cartão, transferência, AliPay, PayPal.

A Decodo (antes Smartproxy) vende proxies residenciais e de datacenter. Residencial: $4/GB sem plano mensal, ou pacotes mensais a partir de $3.75/GB para 3 GB. Pagamentos: cartões, PayPal, Alipay, Google/Apple Pay, cripto (com limites).
Um 200 no Requests prova que aquele hop falou HTTP. Não prova que o próximo alvo aceita o IP, nem que o navegador na mesma máquina usa a mesma saída.
Como configurar um proxy no Python requests?
Por que https no dict aponta para um proxy http?
Como passar usuário e senha sem quebrar caracteres especiais?
Qual a diferença entre socks5 e socks5h no Requests?
Por que um 407 vira exception no HTTPS e resposta no HTTP?
timeout=(3, 10) limita a chamada a 13 segundos?
A página Meu IP no navegador mostra o IP do meu script Python?
Artigos relacionados
Como funcionam os proxies móveis: rotação de IP e sessões
Por que o site ainda reconhece você depois de trocar o IP: do que é feita a saída móvel, por que a operadora usa CGN, os três tipos de "sessão", o que a rotação muda de fato e o que verificar antes de alugar.
Proxies grátis: riscos e limites antes de usar
Proxy grátis é seguro? O que o dono do proxy vê com HTTP e HTTPS, os riscos para suas senhas, lista pública ou teste oficial e como testar sem se expor.
O que é proxy ISP e quando usar IP fixo
Proxy ISP explicado: de onde vem o IP, o que o ASN revela, por que IP estático não é o mesmo que sessão sticky residencial e como checar o produto antes de pagar.



