Proxy no Python Requests: Configuração, Autenticação e Rotação
Configurar um python requests proxy é o primeiro passo real em quase qualquer trabalho de scraping ou monitoramento, e é uma daquelas tarefas que parecem triviais até uma requisição retornar silenciosamente o seu próprio IP ou um erro de autenticação que você não consegue explicar. Este guia resolve isso. Ao final você terá código pronto para copiar e colar para rotear a biblioteca requests por um proxy em HTTP, HTTPS e SOCKS5, adicionar autenticação, reutilizar uma conexão com uma sessão, definir timeouts e retries, rotacionar por um pool, verificar se o IP realmente mudou e tratar os erros que você vai encontrar na prática. O caso de uso honesto ao longo do texto é trabalho legítimo - scraping de dados públicos, monitoramento de preços e SERP e pesquisa de SEO - não algo por trás de um login.
Última atualização: 24 de agosto de 2026. Este post contém links de afiliado - veja nossa divulgação de afiliados. Os planos e endpoints dos provedores mudam, então verifique qualquer número no próprio site do provedor antes de confiar nele.
Como definir um proxy no Python requests
O exemplo funcional mínimo é um dicionário com as chaves http e https, passado ao argumento proxies de qualquer método de requisição:
import requests
proxies = {
"http": "http://198.51.100.10:8080",
"https": "http://198.51.100.10:8080",
}
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.json())
Duas coisas fazem as pessoas tropeçarem aqui. Primeiro, o valor é uma URL de proxy completa, não um IP nu: ele precisa do esquema (http://), do host e da porta. Segundo, as chaves do dicionário não são o protocolo do proxy - elas selecionam qual proxy usar com base no esquema da URL de destino. Uma requisição a um site https:// usa a chave https. Essa distinção se torna importante na próxima seção, e é o motivo isolado mais comum de um proxy "não funcionar".
Sempre passe um timeout, como acima. Um proxy fica entre você e o alvo, então um proxy morto ou lento vai travar seu script para sempre sem um.
Proxies HTTP, HTTPS e SOCKS5
As chaves no dicionário proxies roteiam pelo esquema de destino, enquanto o esquema do valor é o que o próprio proxy fala. Assim, um único proxy HTTP capaz de tunelar tráfego HTTPS é escrito com um valor http:// sob as duas chaves - que é exatamente o que a maioria dos proxies HTTP de datacenter e residenciais são. Você não precisa de um valor https:// só porque está fazendo scraping de sites HTTPS.
SOCKS5 é diferente. Ele precisa de uma dependência extra:
pip install "requests[socks]"
Depois use o esquema socks5h://. O h no final importa: ele envia a resolução de DNS pelo proxy em vez de resolver os hostnames localmente, que é o que você quase sempre quer para scraping, para que o DNS da sua máquina não vaze o alvo.
proxies = {
"http": "socks5h://user:pass@proxy-host:1080",
"https": "socks5h://user:pass@proxy-host:1080",
}
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.json())
| Prefixo do esquema | O que faz |
|---|---|
http:// | Roteia por um proxy HTTP; tunela alvos HTTPS via CONNECT. O padrão para a maioria dos proxies. |
socks5:// | Roteia por SOCKS5, mas resolve o DNS localmente na sua máquina. |
socks5h:// | Roteia por SOCKS5 e resolve o DNS no proxy (o h). Preferido para scraping. |
Autenticação de proxy em Python
A maioria dos proxies pagos exige um nome de usuário e uma senha. Com requests, as credenciais vão direto para a URL do proxy como http://user:pass@host:port:
proxy_url = "http://my-username:my-password@proxy-host:8080"
proxies = {"http": proxy_url, "https": proxy_url}
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.json())
Aqui está o bug que custa uma tarde às pessoas: se sua senha contém caracteres como @, :, # ou /, eles quebram a análise da URL e a autenticação falha sem motivo óbvio. Faça URL-encode do nome de usuário e da senha com urllib.parse.quote antes de montar a URL:
from urllib.parse import quote
user = "my-username"
password = "p@ss:w#rd" # contains reserved characters
host, port = "proxy-host", 8080
proxy_url = f"http://{quote(user, safe='')}:{quote(password, safe='')}@{host}:{port}"
proxies = {"http": proxy_url, "https": proxy_url}
O argumento safe='' diz ao quote para codificar todo caractere reservado em vez de deixar alguns intocados. Faça isso desde o início e você nunca vai perseguir um bug fantasma de "a autenticação falha sem razão". Se o proxy ainda recusar você, o código de status a procurar é 407 Proxy Authentication Required - coberto na seção de erros abaixo.
Reutilize conexões com requests.Session
Para qualquer coisa além de uma requisição única, use uma Session. Defina os proxies uma vez na sessão e toda requisição por ela reutiliza o proxy, o cookie jar e a conexão TCP subjacente:
session = requests.Session()
session.proxies = {
"http": proxy_url,
"https": proxy_url,
}
session.get("https://httpbin.org/ip", timeout=10)
session.get("https://httpbin.org/headers", timeout=10) # same proxy, same cookies
Isso importa para scraping de duas formas. Os cookies persistem, então um login ou estado de sessão segue entre as requisições, e a reutilização de conexão corta a sobrecarga do handshake a cada chamada, o que é um ganho real de velocidade quando você faz milhares de requisições pelo mesmo proxy.
Defina proxies com variáveis de ambiente
O requests lê as configurações de proxy do ambiente automaticamente, então você pode manter as credenciais totalmente fora do seu código:
export HTTP_PROXY="http://user:pass@proxy-host:8080"
export HTTPS_PROXY="http://user:pass@proxy-host:8080"
Tanto os nomes em maiúsculas quanto em minúsculas (http_proxy, https_proxy) são reconhecidos. Algumas notas sobre quando isso é mais limpo:
- Bom para trocar proxies por ambiente (dev, staging, production) sem tocar no código.
- Bom para manter segredos em um arquivo
.envou no cofre de segredos da sua CI, em vez de no repositório. - Para ignorar os proxies de ambiente em uma sessão, defina
session.trust_env = False. Isso é útil quando há um proxy no nível da máquina, mas você quer que um script específico vá direto ou use a própria lista.
Adicione timeouts e retries
Esta é a parte que a maioria dos tutoriais pula, e é a diferença entre um script que morre às 3h da manhã e um que termina. Proxies são mais instáveis que uma conexão direta - um IP pode estar temporariamente sobrecarregado ou com rate limit - então os retries importam mais aqui do que o usual.
Comece com um timeout de verdade. Passar uma tupla o divide em timeouts de conexão e de leitura, então um proxy lento falha rápido na conexão mas ainda permite que uma resposta lenta termine:
response = requests.get(url, proxies=proxies, timeout=(5, 20)) # (connect, read) seconds
Depois monte uma estratégia de retry em uma sessão usando o Retry do urllib3 com um HTTPAdapter. O backoff_factor espaça as tentativas para você não martelar um endpoint em dificuldade, e o status_forcelist refaz nos códigos transitórios de servidor e de rate limit:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
retry = Retry(
total=5,
backoff_factor=1, # waits 0s, 2s, 4s, 8s... between tries
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET", "POST"],
)
session = requests.Session()
adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)
session.proxies = {"http": proxy_url, "https": proxy_url}
response = session.get("https://httpbin.org/ip", timeout=(5, 20))
print(response.json())
Em versões mais antigas do urllib3, o argumento se chama method_whitelist em vez de allowed_methods - atualize a biblioteca se você esbarrar nisso. Note que o Retry trata erros de conexão e os códigos de status que você lista; ele não refaz um 200 limpo que simplesmente retornou uma página de bloqueio, e por isso as seções de rotação e de erros abaixo ainda importam.
Rotacione proxies por um pool
Enviar toda requisição de um só IP é a forma mais rápida de levar rate limit ou bloqueio. A rotação espalha as requisições por muitos IPs. Há duas abordagens honestas, e elas valem o esforço em escalas bem diferentes. Se você quer o conceito primeiro, veja nossa explicação sobre como funcionam os proxies rotativos.
Método A - um pool manual com random.choice
Se você tem um punhado de IPs estáticos, mantenha-os em uma lista e escolha um por requisição. O random.choice dá uma seleção aleatória simples:
import random
import requests
proxy_pool = [
"http://user:pass@ip-1:8080",
"http://user:pass@ip-2:8080",
"http://user:pass@ip-3:8080",
]
targets = ["https://httpbin.org/ip"] * 6
for url in targets:
proxy = random.choice(proxy_pool)
proxies = {"http": proxy, "https": proxy}
try:
r = requests.get(url, proxies=proxies, timeout=10)
print(proxy, "->", r.json()["origin"])
except requests.exceptions.RequestException as exc:
print(f"failed via {proxy}: {exc}")
Para round-robin estrito em vez de aleatório, use itertools.cycle e chame next(proxy_cycle) a cada vez. O Método A serve para um conjunto pequeno e fixo de IPs que você já possui. O custo é que você mantém a lista, remove IPs mortos e acompanha quais um alvo começou a bloquear.
Método B - um endpoint rotativo do provedor
Em escala, você para de manter uma lista e aponta toda requisição para um único endpoint de backbone, deixando o provedor trocar o IP de saída para você. Usando o formato real de endpoint rotativo da Webshare, você acrescenta -rotate ao nome de usuário e envia tudo para p.webshare.io na porta 80:
import requests
# One endpoint; the provider hands you a fresh exit IP per request.
proxy = "http://<username>-rotate:<password>@p.webshare.io:80/"
proxies = {"http": proxy, "https": proxy}
for _ in range(6):
r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(r.json()["origin"]) # typically a different IP each call
O sufixo -rotate pede um novo IP por chamada; se você precisa que o mesmo IP persista para um fluxo de vários passos (uma sessão sticky), os provedores dão, em vez disso, uma forma de id de sessão numérica. Verifique o endpoint exato e o formato do nome de usuário em help.webshare.io antes de confiar neles, já que podem mudar. O ponto do Método B é simples: ele remove todo o fardo de manutenção do Método A, e por isso ele vence assim que você passa de alguns IPs.
Para de fato rodar qualquer um desses trechos sem se comprometer com um plano, o nível gratuito da Webshare dá a você 10 proxies e 1GB de banda mensal (em agosto de 2026, verifique no site), o que basta para testar rotação, autenticação e o código de retry de ponta a ponta. Você pode pegar os proxies gratuitos aqui e colar suas credenciais reais nos exemplos acima.
Uma pequena nota honesta do meu próprio uso: embora o trecho acima rotacione por requisição, no meu scraping eu na verdade fixo uma sessão sticky em vez de pegar um IP novo a cada chamada, e ela manteve o mesmo IP de saída por todo o tempo que o job rodou. Configurar isso pelo endpoint da Webshare foi direto, e eu não bati em erros de autenticação 407 nem de rate 429, então nunca precisei de um espaçamento pesado de requisições para contorná-los. Seus resultados vão variar conforme o alvo, então meça a taxa de sucesso contra suas próprias URLs antes de escalar um job.
Verifique o IP do seu proxy
Antes de confiar em qualquer coisa disso, confirme que o proxy está de fato no caminho. Acesse um serviço de eco de IP com e sem o proxy e compare - se os dois coincidirem, o proxy não está sendo usado:
import requests
def show_ip(proxies=None):
r = requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=10)
return r.json()["ip"]
print("direct: ", show_ip())
print("via proxy:", show_ip({"http": proxy_url, "https": proxy_url}))
Se a linha "via proxy" ainda mostra seu IP real, a causa usual é a falta de uma chave https no dicionário enquanto você requisita uma URL https:// - então a requisição foi direto sem barulho. Adicione a entrada https (veja a seção de configuração) e rode de novo. Você pode trocar api.ipify.org por https://httpbin.org/ip; só leia o campo origin em vez de ip.
Trate os erros de proxy
Envolva as requisições em um try/except e capture as exceções específicas para reagir corretamente em vez de derrubar toda a execução:
import requests
try:
r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
r.raise_for_status()
print(r.json())
except requests.exceptions.ProxyError as exc:
print("proxy dead or blocked:", exc)
except requests.exceptions.ConnectTimeout:
print("proxy did not answer in time")
except requests.exceptions.HTTPError as exc:
print("target returned an error status:", exc.response.status_code)
except requests.exceptions.RequestException as exc:
print("request failed:", exc)
Capture do mais específico ao mais geral; RequestException é a classe base e deve ficar por último, como pega-tudo. Veja como decodificar as falhas comuns:
| Sintoma | Causa provável | Correção |
|---|---|---|
| "Max retries exceeded" / ProxyError | Endpoint de proxy morto, errado ou bloqueado | Confira host/porta, rotacione para outro IP, confirme que o proxy está vivo |
| HTTP 407 | Autenticação de proxy rejeitada | Corrija o usuário/senha; faça URL-encode da senha com quote |
| HTTP 429 | Rate limit pelo alvo | Desacelere, adicione backoff, rotacione IPs, espace as requisições |
| HTTP 403 | O alvo bloqueou este IP ou fingerprint | Rotacione IPs, tente um tipo de proxy mais furtivo, revise os headers da requisição |
| ConnectTimeout | O proxy está no ar mas lento ou sobrecarregado | Aumente o timeout de conexão, refaça, tire o IP lento do pool |
Faça scraping com responsabilidade
Proxies são uma ferramenta para trabalho legítimo: scraping de dados públicos, monitoramento de preços e SERP, verificação de anúncios, pesquisa de mercado e dados de SEO. Mantenha limpo - respeite o robots.txt e os Termos de Serviço de cada site, mire apenas dados disponíveis publicamente, limite sua taxa de requisições para não degradar o servidor de alguém e fique longe de qualquer coisa por trás de um login. Isto é boa prática geral, não aconselhamento jurídico; verifique as regras que se aplicam ao seu próprio projeto e jurisdição. Para o panorama maior de como fazer isso bem, veja nosso guia de proxies para web scraping.
Perguntas frequentes
A biblioteca requests suporta SOCKS5?
Sim, assim que você instala o extra com pip install "requests[socks]". Depois use um valor socks5h:// no dicionário de proxies para que o DNS resolva pelo proxy.
Por que minha requisição ainda mostra meu IP real?
Quase sempre uma chave https faltando enquanto você requisita uma URL HTTPS, então a requisição foi direto. Garanta que as duas chaves http e https estejam definidas e rode de novo o trecho de verificação acima.
Proxies gratuitos servem para scraping em Python?
Para aprender o código, servem. Para trabalhos reais eles são lentos, de vida curta e muitas vezes já bloqueados ou inseguros. Um nível gratuito genuíno de um provedor pago (IPs limitados mas confiáveis) é um jeito melhor de testar exatamente o código antes de pagar por volume.
Como consigo um IP novo em cada requisição?
Ou rotacione um pool você mesmo com random.choice (Método A), ou aponte toda requisição para um endpoint rotativo de provedor como <username>[email protected]:80 (Método B), que troca o IP de saída para você.
Posso usar a mesma configuração de proxy com httpx ou aiohttp?
O conceito se mantém, mas a sintaxe difere - httpx e aiohttp recebem uma URL de proxy ou config por cliente, em vez do mesmo dicionário. Para a linha de comando, veja nosso guia de como usar um proxy com curl, e para o panorama maior nossa visão geral de proxies para web scraping.
Conclusão
O caminho é sempre o mesmo: monte o dicionário proxies, adicione autenticação (fazendo URL-encode da senha), reutilize uma Session, defina timeouts e um adaptador Retry, e então rotacione - um pool manual para poucos IPs, um endpoint rotativo de provedor assim que você escala. Verifique que o IP mudou, capture os erros e faça scraping apenas de dados públicos dentro das regras de cada site. Na hora de escolher um provedor, nossa seleção dos melhores serviços de proxy compara as opções com honestidade. Para rodar tudo acima sem gastar nada primeiro, pegue os proxies gratuitos da Webshare, coloque suas credenciais nos trechos e confirme que cada bloco funciona contra seus próprios alvos antes de escalar.