Resumo: Este guia explica passo a passo como utilizar proxies com o Python Requests de ponta a ponta: umproxies, URLs autenticadas, variáveis de ambiente,Sessionreutilização, SOCKS5 sem fugas de DNS e um conjunto de rotação com tentativas de reenvio e um disjuntor de circuito. No final, saberá quando uma API gerida compensa em relação a um conjunto DIY.
Introdução
Se já lançou um scraper que funcionava localmente e depois começou a devolver erros 403, 429 ou timeouts silenciosos em produção, já sabe por que razão os proxies existem. Aprender a utilizar proxies com o Python Requests é a diferença entre um script que é executado uma vez no seu portátil e uma tarefa que sobrevive a limites de taxa, bloqueios geográficos e proibições de IP em milhares de páginas.
Uma configuração de proxy do Python Requests, na sua forma mais simples, é um dicionário que mapeia http e https a um URL de proxy e é passado para requests.get(). Isso permite-lhe desbloquear o acesso durante dez minutos. A produção precisa de mais: credenciais mantidas fora do git, sessões que mantêm cookies, pontos finais SOCKS5 que não vazam DNS, tentativas com backoff e uma estratégia de rotação que não continue a martelar um proxy inativo.
Este guia destina-se a programadores Python de nível intermédio que já conhecem os conceitos básicos de requests e agora precisam de um caminho fiável para adicionar suporte a proxies sem reescrever o seu scraper. Abordamos como usar proxies com o Python Requests, desde o dicionário trivial até um ciclo de rotação de produção, com as vantagens e desvantagens explicadas em linguagem simples.
Início rápido: um proxy Python Requests funcional em cinco minutos
Antes de nos aprofundarmos na rotação e nas tentativas, eis o exemplo de oito linhas de que 90% dos programadores realmente precisam quando procuram como usar proxies com Python Requests. Coloque-o num ficheiro, substitua por qualquer proxy host:port que funcione e execute.
import requests
proxies = {
"http": "http://203.0.113.10:8080",
"https": "http://203.0.113.10:8080",
}
resp = requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=10)
print(resp.json())Se o IP que for apresentado for o endereço do proxy e não o seu, o seu proxy está no caminho da solicitação. O resto deste guia trata de como reforçar este padrão.
Pré-requisitos: Python, pip e um proxy ao qual consiga aceder
Precisa do Python 3.8 ou posterior (python --version), pipe, pelo menos, um host:porta de proxy utilizável. Um ambiente virtual (python -m venv venv) mantém as dependências organizadas por projeto. Instale o Requests com pip install requests. O proxy pode provir de uma lista gratuita, de um conjunto pago ou de uma instância local do Squid ou do Tor.
Como usar proxies com o Python Requests: o modelo mental
Antes de se debruçar sobre o código, é útil saber como o Requests decide, na verdade, para onde enviar o tráfego. A biblioteca encaminha cada chamada através de um URL de proxy com base no esquema: HTTP, HTTPS e (com um pacote adicional) SOCKS. Três fontes podem fornecer esse URL, nesta ordem aproximada de precedência: o proxies= argumento numa única chamada, o session.proxies dict num Sessione, finalmente, as HTTP_PROXY / HTTPS_PROXY variáveis de ambiente. A precedência exata e o tratamento de variantes em minúsculas estão documentados na documentação de utilização avançada do Requests; confirme sempre com a sua versão fixada.
Configurar um proxy básico com o Python Requests
A configuração básica envolve duas etapas: criar um proxies dicionário e, em seguida, enviar um pedido de verificação através dele. As duas subsecções seguintes explicam cada etapa e as armadilhas que surgem em proxies inativos ou mal configurados.
Crie o dicionário de proxies para HTTP e HTTPS
No Python Requests, os proxies são passados como um dicionário que mapeia esquemas para um URL de proxy. Preencha sempre ambas as chaves, mesmo quando pretender aceder apenas a destinos HTTPS, porque os redirecionamentos podem fazer com que o esquema seja rebaixado.
proxies = {
"http": "http://user:pass@proxy.example.com:8080",
"https": "http://user:pass@proxy.example.com:8080",
}
requests.get(url, proxies=proxies, timeout=(5, 15))O timeout=(connect, read) tupla é imprescindível em produção. Sem ela, um proxy inativo bloqueia o seu worker.
Confirme se o proxy está no caminho da solicitação
Aceda a um ponto final de eco de IP e compare com o seu IP real. Dois pontos finais fiáveis são https://api.ipify.org?format=json e https://httpbin.org/ip.
print(requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=10).json())Se o endereço devolvido for diferente do seu IP local, o proxy está a funcionar. Se corresponder, o proxy falhou silenciosamente na abertura.
Autenticar proxies e proteger credenciais
A maioria dos proxies pagos é autenticada, e é aí que a utilização de proxies com Python Requests se torna mais complicada. As próximas três subsecções abordam a incorporação de URL, variáveis de ambiente e os três códigos de erro que irá encontrar.
Incorporar um nome de utilizador e uma palavra-passe na URL do proxy
O formato aceitável é http://user:pass@host:port. Se a sua palavra-passe contiver @, :, %, ou /, codifique-a para URL, caso contrário o Requests irá interpretar mal a URL e irá ver erros 407:
from urllib.parse import quote
user = quote("alice@corp")
pwd = quote("p@ss:w/rd%1")
proxy_url = f"http://{user}:{pwd}@proxy.example.com:8080"Nunca suba essa string para o git.
Mova os segredos para HTTP_PROXY, HTTPS_PROXY e NO_PROXY
O Requests deteta automaticamente HTTP_PROXY, HTTPS_PROXY, e NO_PROXY do ambiente e, de acordo com a documentação oficial, também aceita variantes em minúsculas em sistemas POSIX. Isso significa que pode manter as credenciais totalmente fora do código:
# Linux / macOS
export HTTPS_PROXY="http://user:pass@proxy.example.com:8080"
export NO_PROXY="localhost,127.0.0.1,.internal"# Windows
setx HTTPS_PROXY "http://user:pass@proxy.example.com:8080"Este é o padrão mais limpo para imagens Docker e executores de CI, onde os segredos residem no ambiente e não no repositório.
Diagnosticar erros de proxy 407, 401 e 403
Quando algo está errado, o código de estado indica-lhe qual a camada que está com problemas.
|
Estado |
Causa provável |
Correção em uma linha |
|---|---|---|
|
407 Autenticação de proxy necessária |
Credenciais de proxy em falta ou incorretas |
Codifique a senha em URL e teste novamente |
|
401 Não autorizado |
Nome de utilizador ou palavra-passe incorretos |
Altere as credenciais e verifique com |
|
403 Proibido |
O site de destino bloqueou o IP do proxy |
Mude para outro proxy ou altere a localização geográfica |
Verifique primeiro o proxy e, em seguida, o destino.
Reutilize as configurações com requests.Session para cookies e pool de conexões
A Session é a primitiva certa assim que fizer mais do que uma chamada. Mantém proxies, cabeçalhos padrão e cookies, e mantém a ligação TCP subjacente ativa para que não tenha de pagar por um novo handshake TLS a cada acesso. A sessão está integrada no Requests, pelo que não há nada extra para instalar.
session = requests.Session()
session.proxies = proxies
session.headers.update({"User-Agent": "my-scraper/1.0"})
session.post("https://example.com/login", data={"u": "alice", "p": "secret"})
dashboard = session.get("https://example.com/dashboard") # cookies persist
print(dashboard.status_code, len(dashboard.content))A mesma sessão abrange .text, .json(), e .content, pelo que os downloads de texto, JSON e binários passam todos pelo mesmo proxy de sessão do Python Requests sem necessidade de reconfiguração.
Use proxies SOCKS5 via requests[socks]
O Requests não suporta SOCKS de fábrica. Incorpora o PySocks com o socks extra:
pip install "requests[socks]"Em seguida, use o socks5h:// scheme. O h indica ao PySocks para resolver o DNS através do proxy em vez de localmente, o que é o que se pretende quando não se confia no resolvedor do ISP ou se está a utilizar o Tor.
proxies = {
"http": "socks5h://127.0.0.1:9050", # Tor default
"https": "socks5h://127.0.0.1:9050",
}
requests.get("https://check.torproject.org/", proxies=proxies, timeout=15)O socks5:// resolve o DNS localmente e revela discretamente os nomes de host que visita.
Alterne proxies para evitar bloqueios e limites de taxa
Um único IP fica sujeito a limites de taxa e, eventualmente, bloqueado. A verdadeira resposta para como usar proxies com Python Requests em escala é a rotação, e as próximas três subsecções mostram padrões de maturidade crescente.
Rotação aleatória com um ciclo de repetição
O padrão mais simples é random.choice sobre uma lista de proxies, envolvida num ciclo de tentativas:
import random, requests
from requests.exceptions import RequestException
PROXIES = [{"http": p, "https": p} for p in PROXY_URLS]
def fetch(url, attempts=4):
for _ in range(attempts):
proxy = random.choice(PROXIES)
try:
return requests.get(url, proxies=proxy, timeout=10)
except RequestException:
continue
raise RuntimeError("all attempts failed")Funciona, mas a aleatoriedade pura tende a escolher repetidamente proxies inativos e ignora a carga.
Escolhas em potências de dois para um balanceamento de carga mais inteligente
Um refinamento bem estudado é a escolha de potência de dois: para cada pedido, sorteia-se dois proxies aleatoriamente e utiliza-se aquele que está atualmente a tratar de menos chamadas em curso. A intuição, apoiada pela literatura sobre equilíbrio de carga comumente atribuída à análise de Mitzenmacher de 2001, é que isto atenua a carga no pior dos casos muito melhor do que a aleatoriedade uniforme, mantendo-se económico.
import random
LOAD = {p: 0 for p in PROXY_URLS}
def pick():
a, b = random.sample(PROXY_URLS, 2)
return a if LOAD[a] <= LOAD[b] else bAumente LOAD[proxy] antes da solicitação e diminua depois. Os ganhos exatos dependem do tamanho do pool; faça um benchmark antes de citar números.
Adicione um disjuntor para que os proxies inativos deixem de desperdiçar pedidos
Tanto o aleatório como o poder de dois continuam a selecionar um proxy inativo até que este tenha sucesso. Um disjuntor resolve isso. Acompanhe o estado por proxy: CLOSED (ativo), OPEN (ignorada) e HALF_OPEN (em período de prova).
import time
state = {p: {"fail": 0, "open_until": 0} for p in PROXY_URLS}
MAX_FAILS, COOLDOWN = 3, 60
def usable(p):
return time.time() >= state[p]["open_until"]
def record(p, ok):
if ok:
state[p]["fail"] = 0
else:
state[p]["fail"] += 1
if state[p]["fail"] >= MAX_FAILS:
state[p]["open_until"] = time.time() + COOLDOWNApós o tempo de espera, envie uma solicitação probatória ao proxy antes de o reativar totalmente.
Repetir pedidos falhados com HTTPAdapter e urllib3 Repetir
Montar um HTTPAdapter com uma urllib3 Retry política numa Sessão aplica tentativas de repetição a todas as chamadas HTTP e HTTPS dessa sessão. Fixar urllib3 (por exemplo, urllib3==2.2.*) para que os nomes dos parâmetros permaneçam estáveis ao longo das atualizações.
from requests import Session
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
retry = Retry(
total=3,
status_forcelist=[429, 500, 502, 503, 504],
backoff_factor=2,
allowed_methods=["GET", "POST"],
respect_retry_after_header=True,
)
adapter = HTTPAdapter(max_retries=retry)
s = Session()
s.mount("http://", adapter)
s.mount("https://", adapter)Com backoff_factor=2, o urllib3 fica inativo por cerca de backoff_factor * (2 ** (n - 1)) segundos entre tentativas (cerca de 2, 4, 8 s). Combine as tentativas com a rotação para que cada nova tentativa também escolha um novo proxy.
Lidar com a verificação SSL e certificados de proxy autoassinados
Se um proxy apresentar um certificado autoassinado, verify=False ignora o aviso, mas deixa-o vulnerável a ataques man-in-the-middle, por isso use-o apenas em proxies locais de confiança ou em testes. A solução mais segura é adicionar o proxy ou o pacote de CAs corporativas ao armazenamento de confiança através de verify="/path/to/ca.pem" ou REQUESTS_CA_BUNDLE. Suprima InsecureRequestWarning apenas depois de ter feito deliberadamente a escolha de segurança.
Quando trocar o conjunto de proxies DIY por uma API de scraping gerida
Execute esta lista de verificação. Se marcar três ou mais itens, um proxy gerido ou uma API de scraping é normalmente mais barato do que o seu tempo:
- Precisa de segmentação geográfica em mais de dois países.
- Os bloqueios custam receitas reais, não apenas uma nova tentativa.
- Os alvos renderizam conteúdo com JavaScript.
- Um engenheiro sénior passa um dia por semana a supervisionar o conjunto de proxies.
- A conformidade exige IPs residenciais auditados.
Pontos-chave
- A resposta mais curta sobre como usar proxies com Python Requests é um dicionário que mapeia
httpehttpsa um URL de proxy, passado atravésproxies=com umtimeout. - Mantenha as credenciais fora do código-fonte: prefira
HTTP_PROXY,HTTPS_PROXY, eNO_PROXYvariáveis de ambiente, e codificar por URL os caracteres especiais nas senhas. - Um
requests.Sessionpersiste proxies, cabeçalhos e cookies e reutiliza ligações TCP, o que é a configuração padrão adequada para qualquer fluxo de trabalho com múltiplas chamadas. - A rotação em produção combina opções de potência de dois com um disjuntor e uma
HTTPAdapterRetrypolítica que resiste a erros 429 e 5xx. - Para SOCKS5, instale
requests[socks]e utilizesocks5h://para que o DNS seja resolvido através do proxy em vez de vazar localmente.
Recursos relacionados da WebScrapingAPI
Perguntas frequentes
O Python Requests suporta proxies SOCKS5 de forma nativa?
Não. A instalação base requests apenas inclui suporte para HTTP e HTTPS. Execute pip install "requests[socks]" para instalar o PySocks e, em seguida, use um socks5:// ou, de preferência, socks5h:// uma URL no seu proxies dict. Esse é o caminho mais simples para o suporte a SOCKS.
Por que é que as minhas solicitações por proxy continuam a revelar o meu IP real através de pesquisas de DNS?
Porque o socks5:// esquema diz ao PySocks para resolver nomes de host localmente antes de tunelar a ligação. Mude para socks5h://, onde o h significa resolução remota de nomes de host, de modo que as consultas DNS passam pelo servidor SOCKS. Isto é mais importante para o Tor ou qualquer modelo de ameaça em que o seu resolvedor DNS não seja confiável ou seja monitorado.
Como faço para codificar por URL uma senha de proxy que contém os caracteres @, : ou %?
Use urllib.parse.quote da biblioteca padrão: quote("p@ss:w/rd%1") torna-se p%40ss%3Aw%2Frd%251. Incorpore o valor codificado em http://user:encoded_pwd@host:port. Sem a codificação, esses caracteres encerram o segmento de informações do utilizador prematuramente, e irá receber um erro 407 Proxy Authentication Required mesmo quando a palavra-passe estiver tecnicamente correta.
Como faço para indicar ao Python Requests para ignorar o proxy para localhost ou domínios internos?
Defina NO_PROXY para uma lista separada por vírgulas de hosts ou sufixos de domínio, por exemplo NO_PROXY="localhost,127.0.0.1,.internal,.svc.cluster.local". O Requests respeita as variantes em maiúsculas e minúsculas em sistemas POSIX. Para substituições por chamada, passe proxies={"http": None, "https": None} para ignorar qualquer proxy ao nível da sessão.
Quando devo mudar de um conjunto de proxies rotativos DIY para uma API de scraping gerida?
Quando o custo operacional ultrapassa o valor da fatura. Gatilhos concretos: os bloqueios custam mais do que uma nova tentativa, precisa de IPs residenciais em vários países, os alvos têm muito JavaScript ou gasta mais do que algumas horas de engenharia por semana a ajustar o conjunto. Abaixo disso, um pequeno conjunto DIY com novas tentativas e um disjuntor geralmente é suficiente.
Conclusão
Saber como usar proxies com Python Requests tem menos a ver com um único truque e mais com camadas: um proxies para começar, credenciais em variáveis de ambiente para que os segredos fiquem fora do git, um Session para reutilização de ligações e cookies, socks5h:// quando as fugas de DNS importam, e rotação mais tentativas de nova ligação quando um IP já não é suficiente. Combine as opções de potência de dois com um disjuntor e uma HTTPAdapter Retry política, e o seu scraper deixa de falhar no momento em que um proxy fica inativo ou um alvo devolve erros 429.
A certa altura, todas as equipas chegam a um ponto em que gerir o conjunto de proxies custa mais do que o valor dos dados. Se os seus alvos forem fortemente protegidos, específicos de uma localização geográfica ou renderizados em JavaScript, uma opção gerida como a API WebScrapingAPI Scraper trata da camada de pedidos, rotação e desbloqueio por trás de um único ponto de acesso, para que possa manter o código de análise que já escreveu e apenas substituir a etapa de obtenção. Use a lista de verificação acima para decidir; se três ou mais itens estiverem marcados, a matemática favorece a infraestrutura gerida em vez de mais uma ronda de manutenção do conjunto. De qualquer forma, os padrões neste guia devem manter o seu requests-baseado em bom estado, desde o protótipo até à produção.




