Configuração de proxy no Scrapy: usar IPs diferentes por requisição com meta proxy
Este guia mostra como conectar proxies HTTP da Socks5Proxy no Scrapy via meta proxy, middleware para rotacionar IPs da API por requisição, e configuração de velocidade adaptada ao site alvo.
Como o Scrapy lida com proxies?
O Scrapy tem HttpProxyMiddleware ativado por padrão. Adicione o endereço do proxy ao dicionário meta da requisição com a chave proxy, e o middleware converterá o nome de usuário e senha no cabeçalho Proxy-Authorization. URLs HTTPS passam por um túnel CONNECT.
O handler de download padrão do Scrapy suporta proxies HTTP. Se SOCKS5 for essencial, será necessário um handler personalizado, por isso recomendamos usar a porta HTTP do mesmo IP no Scrapy. O IP visto pelo site de destino será o mesmo.
O exemplo usa IP 198.51.100.23, porta HTTP 8000, nome de usuário spx_user e senha spx_pass.
pip install scrapy
scrapy startproject shop
cd shopComo adicionar um proxy a uma solicitação?
Adicione proxy ao meta de Request em start_requests. Repita o processo para requisições subsequentes nos callbacks. Para manter a sessão, passe o valor proxy do meta da resposta anterior.
import scrapy
PROXY = "http://spx_user:spx_pass@198.51.100.23:8000"
class IpCheckSpider(scrapy.Spider):
name = "ip_check"
def start_requests(self):
yield scrapy.Request("https://api.ipify.org?format=json", meta={"proxy": PROXY})
def parse(self, response):
self.logger.info("seen as %s", response.json()["ip"])Como rotacionar IPs a cada solicitação?
Crie um middleware de download para adicionar o próximo proxy a todas as solicitações, permitindo a rotação sem alterar o código do spider. O middleware abaixo recebe a lista via API ao iniciar e mantém o proxy na meta se já estiver presente, permitindo o uso combinado de sessão fixa e rotação.
Armazene chaves API em settings.py ou leia de variáveis de ambiente. Registre com número menor que HttpProxyMiddleware(750) para que o middleware base processe os endereços inseridos.
import itertools
import requests
class RotatingProxyMiddleware:
def __init__(self, key):
text = requests.get(
"https://socks5proxy.io/api/v1/proxies/download",
params={"format": "user:pass@ip:port", "protocol": "http"},
headers={"Authorization": "Bearer " + key},
timeout=30,
).text
self.pool = itertools.cycle(["http://" + l.strip() for l in text.splitlines() if l.strip()])
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings.get("SPX_API_KEY"))
def process_request(self, request, spider):
if "proxy" not in request.meta: # keep a proxy that was set on purpose (sticky sessions)
request.meta["proxy"] = next(self.pool)SPX_API_KEY = "YOUR_API_KEY"
DOWNLOADER_MIDDLEWARES = {
"shop.middlewares.RotatingProxyMiddleware": 740,
}
CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 16
DOWNLOAD_DELAY = 0.25
AUTOTHROTTLE_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [429, 500, 502, 503, 504, 522, 524, 408]
DOWNLOAD_TIMEOUT = 30Como ajustar velocidade e tentativas?
CONCURRENT_REQUESTS_PER_DOMAIN define requisições simultâneas para o mesmo domínio. Com mais proxies, você pode aumentar este valor mantendo a carga por IP. Por exemplo, 500 IPs com 50 requisições simultâneas usam cada IP em média apenas 1 vez a cada 10 requisições.
AUTOTHROTTLE ajusta automaticamente intervalos entre requisições conforme a velocidade de resposta. Para muitos erros 429, use RETRY_HTTP_CODES para tentar novamente, removendo o proxy do meta para que o middleware tente o próximo proxy.
Inclua uma etapa para verificar se os resultados são páginas reais, não telas de confirmação. Se elementos esperados estiverem faltando, reenvie a requisição por outro IP.
- Ajuste requisições simultâneas por domínio conforme número de IPs
- AUTOTHROTTLE ajusta intervalos conforme velocidade de resposta
- Para erros 429 e 5xx, tente novamente com outro IP
- Filtrar CAPTCHAs via inspeção de conteúdo
O que muda com autorização por IP?
Registre o IPv4 do servidor Scrapy no dashboard para usar meta proxy sem credenciais, como http://198.51.100.23:8000. Você também pode baixar listas no formato ip:port. Se usar vários servidores, registre todos os IPs (até 10).
Como agrupar requisições com sessão no mesmo IP?
Para fluxos que exigem continuidade de cookies, como login ou carrinho de compras, é necessário usar o mesmo IP. Insira o meta proxy diretamente na primeira solicitação e passe o valor de proxy de response.meta para a próxima solicitação no callback, para que o middleware de ciclo não o altere. Usar a chave meta cookiejar do Scrapy também ajuda a separar os cookies por sessão.
Vinculando um proxy e cookies a cada sessão, múltiplas sessões podem operar simultaneamente sem interferência.
import scrapy
PROXIES = [
"http://spx_user:spx_pass@198.51.100.23:8000",
"http://spx_user:spx_pass@198.51.100.24:8000",
]
class SessionSpider(scrapy.Spider):
name = "sessions"
def start_requests(self):
for i, proxy in enumerate(PROXIES):
yield scrapy.Request("https://example.com/", meta={"proxy": proxy, "cookiejar": i}, dont_filter=True)
def parse(self, response):
# follow-up request keeps the same proxy and the same cookie jar
yield response.follow("/account", meta={"proxy": response.meta["proxy"], "cookiejar": response.meta["cookiejar"]}, callback=self.parse_account)
def parse_account(self, response):
self.logger.info("status %s via %s", response.status, response.meta["proxy"])Como remover temporariamente um proxy com falha?
No middleware, se você receber uma resposta 403 ou 429 no process_response, pode pausar o uso desse proxy por alguns minutos e enviar a mesma solicitação através de outro proxy. Copie a solicitação, remova o proxy do meta, ative dont_filter e retorne para que o próximo proxy seja usado.
Gerencie listas de proxies em pausa e horários de reutilização em um dicionário. Evitar reuso imediato do mesmo IP dá tempo para limites do site serem resetados.
Quais configurações economizam largura de banda no Scrapy?
O Scrapy recebe apenas HTML por padrão, consumindo muito menos largura de banda que ferramentas baseadas em navegador. Com o HttpCompressionMiddleware ativado por padrão para respostas compactadas, o volume de dados é ainda menor. Por isso, é possível coletar muitas páginas mesmo dentro da largura de banda mensal de planos compartilhados.
Ative HTTPCACHE_ENABLED durante o desenvolvimento para evitar requisições repetidas ao mesmo site. Em produção, mantenha a filtragem de URLs duplicados (ativada por padrão) e use dont_filter apenas para requisições que precisam ser refeitas.
Também é importante limitar o escopo de links seguidos para evitar navegar em subpáginas desnecessárias. Definir claramente o escopo da coleta reduz tempo, largura de banda e a carga no site alvo.
Como resolver problemas frequentes?
Se receber resposta 407, verifique o nome de usuário e senha no endereço. Se a senha tiver caracteres especiais, codifique-os com percent-encoding. TunnelError ocorre quando o proxy não aceita requisições CONNECT - confira se está usando a porta HTTP.
Se todas as solicitações forem feitas pelo mesmo IP, pode ser que o middleware esteja após o HttpProxyMiddleware ou que o spider esteja inserindo meta proxy diretamente. Verifique a ordem no settings.py e o código do spider.