Middleware de proxy no Scrapy: guia completo de configuração (2026)

Publicado em 4 de junho de 2026 · ≈11 min de leitura

O Scrapy continua sendo o cavalo de batalha para crawls em produção em 2026 — e ainda é o framework onde a configuração de proxy mais confunde as pessoas, porque há quatro lugares diferentes para plugar um proxy e três deles estão errados para a maioria dos projetos. Este guia te dá o certo: um pequeno middleware personalizado com roteamento por requisição, sessões sticky, detecção de banimento e comportamento de retentativa sensato.

Se você está usando requests/httpx/aiohttp puros, veja Como Rotacionar Proxies em Python. Este artigo é específico do Scrapy.

A Versão de 30 Segundos

Para um gateway residencial rotativo, a configuração mínima viável é uma linha por requisição — sem necessidade de middleware:

def start_requests(self):
    for url in self.urls:
        yield scrapy.Request(
            url,
            meta={"proxy": "http://USERNAME:PASSWORD@us.jibaoproxy.com:913"},
        )

O HttpProxyMiddleware embutido do Scrapy lê request.meta["proxy"] e cuida da autenticação a partir da URL. O gateway rotaciona o IP de saída para você. Se é só disso que você precisa, pare por aqui. O resto deste guia é para quando você precisa de controle: sessões sticky, roteamento por país, rotação consciente de banimentos e ajuste de concorrência.

Um Middleware de Proxy para Produção

Coloque isto em middlewares.py. Ele atribui sessões sticky por domínio, rotaciona em banimentos e marca cada requisição para que você possa depurar qual sessão buscou o quê:

import random
import string

GATEWAY = "us.jibaoproxy.com:913"
USERNAME = "USERNAME"          # move to settings.py / env in real projects
PASSWORD = "PASSWORD"

def _new_session(n=8):
    return "".join(random.choices(string.ascii_lowercase + string.digits, k=n))

class JibaoProxyMiddleware:
    """Sticky session per domain; rotate session on ban."""

    def __init__(self):
        self.sessions = {}          # domain -> session id

    def _proxy_url(self, session_id):
        user = f"{USERNAME}-session-{session_id}"
        return f"http://{user}:{PASSWORD}@{GATEWAY}"

    def process_request(self, request, spider):
        domain = request.url.split("/")[2]
        session = self.sessions.setdefault(domain, _new_session())
        request.meta["proxy"] = self._proxy_url(session)
        request.meta["proxy_session"] = session

    def rotate(self, domain):
        """Call when a session is burned."""
        self.sessions[domain] = _new_session()

E um downloader middleware companheiro que detecta banimentos e refaz a requisição em uma sessão nova:

from scrapy.downloadermiddlewares.retry import RetryMiddleware
from scrapy.utils.response import response_status_message

BAN_CODES = {403, 429}
BAN_MARKERS = (b"captcha", b"access denied", b"unusual traffic")

class BanAwareRetryMiddleware(RetryMiddleware):

    def process_response(self, request, response, spider):
        banned = (
            response.status in BAN_CODES
            or any(m in response.body[:2048].lower() for m in BAN_MARKERS)
        )
        if banned:
            domain = request.url.split("/")[2]
            proxy_mw = spider.crawler.engine.downloader.middleware.middlewares
            for mw in proxy_mw:
                if hasattr(mw, "rotate"):
                    mw.rotate(domain)        # burn the session
            reason = response_status_message(response.status)
            return self._retry(request, reason, spider) or response
        return super().process_response(request, response, spider)

Conecte os dois em settings.py:

DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.JibaoProxyMiddleware": 350,
    "scrapy.downloadermiddlewares.retry.RetryMiddleware": None,   # replace stock retry
    "myproject.middlewares.BanAwareRetryMiddleware": 550,
}
RETRY_TIMES = 2

A prioridade importa: o middleware de proxy precisa rodar antes do HttpProxyMiddleware (750) do Scrapy, então qualquer valor abaixo de 750 funciona; 350 o mantém cedo e previsível.

Sticky vs Rotativo: Qual Modo para Qual Spider

Tipo de crawlModoImplementação
Coleta de páginas sem estadoRotativoUsername simples, o gateway rotaciona por requisição
Login + crawl atrás de autenticaçãoSticky por conta-session-{account_id}, nunca rotacionar no meio do login
Listagens com muita paginaçãoSticky por domínio, rotaciona em banimentoO middleware acima
Preços específicos por regiãoRotativo + fixação de paísParâmetros no estilo USERNAME-country-de

Tratamento mais aprofundado desse trade-off: Sessões de Proxy Sticky vs Rotativas.

Configurações de Concorrência Que Não Te Banem

Os padrões do Scrapy são ajustados para crawling educado de IP único. Atrás de um pool rotativo você pode forçar muito mais — mas os limites por domínio ainda importam, porque o alvo vê o comportamento agregado:

# settings.py - sane starting point behind a residential pool
CONCURRENT_REQUESTS = 64
CONCURRENT_REQUESTS_PER_DOMAIN = 8     # what the target experiences
DOWNLOAD_DELAY = 0.25                  # jitter applied per slot
RANDOMIZE_DOWNLOAD_DELAY = True        # 0.5x-1.5x the delay
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_TARGET_CONCURRENCY = 6.0
DOWNLOAD_TIMEOUT = 30
ROBOTSTXT_OBEY = True

Aumente CONCURRENT_REQUESTS_PER_DOMAIN só depois de observar sua taxa de 403 no nível atual por alguns milhares de requisições. Ir de 8 → 32 porque "os proxies rotacionam de qualquer jeito" é como as pessoas queimam GB em retentativas.

Disciplina de Largura de Banda (GB Residenciais São Dinheiro)

Falhas Comuns e o Que Elas Realmente Significam

407 Proxy Authentication Required

As credenciais não chegaram ao proxy. Coloque-as na URL (http://user:pass@host:port) em meta["proxy"] — o Scrapy faz o parse e define Proxy-Authorization para você. Definir o cabeçalho manualmente e usar credenciais na URL causa esquisitices de dupla autenticação; escolha uma.

TunnelError: Could not open CONNECT tunnel

Quase sempre um host/porta digitado errado, ou um alvo HTTPS através de um endpoint que não permite CONNECT naquela porta. Verifique com curl -x fora do Scrapy primeiro.

O spider funciona por 10 minutos, depois tudo vira 403

Sua sessão sticky sobreviveu ao seu tempo de bem-vinda, ou sua taxa por domínio está quente demais. O middleware consciente de banimentos acima trata o primeiro caso; reduza CONCURRENT_REQUESTS_PER_DOMAIN para o segundo. Se for um alvo que verifica JA4, a própria pilha TLS do Scrapy pode ser o que te entrega — veja JA3/JA4 explicados para entender por que nenhum proxy resolve isso.

Ferramenta grátis · sem cadastro

Valide sua lista de proxies antes do crawl

Cole os endpoints no nosso Proxy Checker: ele testa conectividade, latência, nível de anonimato e tipo de IP de saída em massa — pegue proxies mortos ou mal rotulados antes que o Scrapy desperdice retentativas com eles.

Verificar meus proxies →

Cansado de ficar babá de listas grátis? Um gateway residencial substitui tudo isso — ganhe 500MB de tráfego grátis →

Resumo

Aponte Seus Spiders para um Pool de Verdade

Sessões residenciais rotativas e sticky em um único gateway. 500MB de tráfego grátis para crawlear.

Começar Teste Grátis

Para todos os produtos de IP · um enorme pool de nós disponíveis a qualquer momento

Cadastre-se agora e ganhe até 100% de reembolso na sua recarga

Novos usuários recebem 500MB ao se cadastrar, mais um bônus na primeira recarga. Oferta por tempo limitado.