Rotação de Proxy no Crawlee para Python: Guia de ProxyConfiguration e SessionPool

Aprenda a implementar rotação de proxy no Crawlee para Python usando ProxyConfiguration, SessionPool e proxies residenciais. Exemplos executáveis, padrões de produção e armadilhas reais.

Proxy Rotation in Crawlee for Python: A Developer's Guide to Residential IPs

Aviso legal: Este guia aborda coleta de dados públicos apenas. Sempre respeite o robots.txt, os Termos de Serviço dos sites, e legislações aplicáveis como o CFAA nos EUA e o GDPR na UE. Prefira APIs oficiais quando disponíveis. O uso de proxies para contornar bloqueios deve ser ético e proporcional.

Se você está construindo crawlers em Python com o Crawlee e seus requests começam a retornar 403 Forbidden após as primeiras 50 requisições, você não está sozinho. A rotação de proxy no Crawlee para Python é a diferença entre um crawler que coleta milhares de páginas e um que morre após minutos de execução. Este guia mostra como integrar proxies residenciais de forma idiomática usando ProxyConfiguration e SessionPool, com exemplos executáveis e padrões de produção.

Como funciona a rotação de proxy no Crawlee para Python

O Crawlee para Python (o port da stack Apify Crawlee) oferece uma arquitetura onde BeautifulSoupCrawler e PlaywrightCrawler operam sobre uma fila de requests unificada, com autoscaling automático e um SessionPool que vincula cookies, headers e fingerprints a IPs específicos. A classe ProxyConfiguration é o ponto de extensão idiomático para gerenciar proxies — ela gera URLs de proxy por sessão ou por requisição, e se integra diretamente ao SessionPool.

Quando você passa um ProxyConfiguration para o construtor do crawler, o framework automaticamente:

  • Atribui um proxy a cada sessão no SessionPool;
  • Mantém o mesmo IP para todas as requisições dentro de uma sessão (sticky session);
  • Rotaciona para um novo IP quando a sessão é retirada via session.retire();
  • Repassa o proxy configurado para o BeautifulSoupCrawler (via httpx) ou para o PlaywrightCrawler (via o contexto do browser).

Isso significa que a rotação de proxy não é um hack externo — é parte do ciclo de vida de sessões do framework.

Arquitetura do Crawlee: BeautifulSoupCrawler, PlaywrightCrawler e SessionPool

Antes de mergulhar na configuração de proxy, é importante entender como o Crawlee estrutura o processamento de requests.

BeautifulSoupCrawler vs PlaywrightCrawler

O BeautifulSoupCrawler usa httpx para fazer requisições HTTP e BeautifulSoup para parsing. É rápido — tipicamente 200-500ms por request — e ideal para sites estáticos ou que retornem HTML completo sem necessidade de execução de JavaScript.

O PlaywrightCrawler usa um browser headless (Chromium, Firefox, ou WebKit) via Playwright. É mais lento — 2-5 segundos por page load — mas necessário para SPAs (Single Page Applications) que renderizam conteúdo via JavaScript.

SessionPool: cookies, fingerprints e IPs

O SessionPool é o componente que torna a rotação de proxy eficaz. Cada sessão no pool carrega:

  • Cookies acumulados durante a navegação;
  • Headers HTTP consistentes (User-Agent, Accept, etc.);
  • Um proxy vinculado — se você configurou ProxyConfiguration, a sessão mantém o mesmo IP até ser retirada.

Isso é crítico: se você rotaciona IPs a cada request mas mantém os mesmos cookies, o site-alvo detecta a inconsistência (cookies de sessão A vindos de IP B) e bloqueia. O Crawlee resolve isso amarrando cookies ao IP dentro de cada sessão.

Autoscaling e concorrência

O Crawlee usa um AutoscaledPool que ajusta a concorrência dinamicamente com base na taxa de sucesso e na latência das requisições. Se a taxa de erro sobe, o pool reduz a concorrência automaticamente. Isso significa que proxies ruins não apenas geram erros — eles também reduzem o throughput do crawler inteiro.

ProxyConfiguration: a API idiomática do Crawlee

A classe ProxyConfiguration é o ponto de extensão correto para gerenciar proxies no Crawlee. Ela expõe o método new_url(), que retorna uma URL de proxy formatada para uma sessão específica.

Rotação round-robin vs sessões sticky

Existem duas estratégias principais:

Round-robin — cada chamada a new_url() sem session_id retorna um proxy diferente:

from crawlee.proxy_configuration import ProxyConfiguration

proxy_config = ProxyConfiguration(proxy_urls=[
    'http://user:pass@gate.proxyhat.com:8080',
    'http://user:pass@gate.proxyhat.com:8080',
    'http://user:pass@gate.proxyhat.com:8080',
])

# Cada chamada retorna um proxy diferente
url1 = await proxy_config.new_url()
url2 = await proxy_config.new_url()

Sticky session — passe um session_id e o mesmo IP é mantido para aquela sessão:

# Mesmo session_id = mesmo IP
url = await proxy_config.new_url(session_id='abc123')

Para a maioria dos casos de produção, sessões sticky são superiores. Sites de e-commerce, redes sociais e plataformas de tickets vinculam carrinhos, sessões de login e tokens CSRF a IPs. Rotacionar IP a cada request quebra essas sessões.

Integrando ProxyConfiguration com o SessionPool

O Crawlee conecta automaticamente o ProxyConfiguration ao SessionPool. Quando você cria um crawler com proxy_configuration, o framework:

  1. Cria uma sessão no pool;
  2. Chama proxy_configuration.new_url(session_id=session.id);
  3. Vincula o proxy retornado à sessão;
  4. Usa esse proxy para todas as requisições da sessão;
  5. Quando session.retire() é chamado, a sessão é descartada e uma nova é criada com um novo proxy.

Isso é o padrão idiomático — não há necessidade de gerenciar proxies manualmente no request_handler.

Por que proxies residenciais superam datacenter em sites com anti-bot

Sites protegidos por Cloudflare, DataDome, PerimeterX e Akamai Bot Manager usam listas de IPs de datacenter conhecidas. O Cloudflare mantém um banco de dados de ranges ASN associados a provedores de hospedagem (AWS, GCP, DigitalOcean, etc.) e aplica desafios automaticamente a esses IPs.

Proxies residenciais usam IPs de ISPs reais (Comcast, AT&T, Vodafone, Telefonica), tornando o tráfego indistinguível de visitantes humanos. A diferença é dramática:

Métrica Datacenter Proxy Residencial Proxy
Taxa de bloqueio (Cloudflare) 60-90% 5-15%
Latência média 50-200ms 300-800ms
Custo por GB $0.5-$2 $3-$15
Concorrência recomendada 50-100 10-30

Estratégia de proxy em camadas (tiered fallback)

Para maximizar custo-eficiência, muitos crawlers de produção usam uma estratégia em camadas:

  1. Camada 1 — Datacenter: tenta primeiro; se receber 403, retira a sessão;
  2. Camada 2 — Residencial: faz retry com proxy residencial;
  3. Camada 3 — Mobile: último recurso para sites extremamente protegidos.

No Crawlee, isso pode ser implementado com múltiplas ProxyConfiguration instâncias e lógica de fallback no request_handler.

Exemplo executável: BeautifulSoupCrawler com ProxyConfiguration e ProxyHat

Aqui está um exemplo completo de um crawler que usa proxies residenciais do ProxyHat com sessões sticky por país:

import asyncio
import hashlib
from crawlee.beautifulsoup_crawler import BeautifulSoupCrawler
from crawlee.beautifulsoup_crawler import BeautifulSoupCrawlingContext
from crawlee.proxy_configuration import ProxyConfiguration
from crawlee.sessions import SessionPool

PROXYHAT_GATEWAY = 'gate.proxyhat.com'
PROXYHAT_PORT = 8080
PROXYHAT_USER = 'seu_usuario'
PROXYHAT_PASS = 'sua_senha'

def build_proxy_url(session_id: str, country: str = 'US') -> str:
    """Gera uma URL de proxy ProxyHat com país e sessão fixos."""
    username = f'{PROXYHAT_USER}-country-{country}-session-{session_id}'
    return f'http://{username}:{PROXYHAT_PASS}@{PROXYHAT_GATEWAY}:{PROXYHAT_PORT}'

class ProxyHatConfiguration(ProxyConfiguration):
    """ProxyConfiguration customizada que gera URLs ProxyHat por sessão."""

    async def new_url(self, session_id: str | None = None) -> str:
        if session_id is None:
            # Sem session_id = round-robin (sem flag de sessão)
            username = f'{PROXYHAT_USER}-country-US'
            return f'http://{username}:{PROXYHAT_PASS}@{PROXYHAT_GATEWAY}:{PROXYHAT_PORT}'
        # Com session_id = sticky session
        sid = hashlib.md5(session_id.encode()).hexdigest()[:12]
        return build_proxy_url(sid, country='US')

async def main():
    proxy_config = ProxyHatConfiguration()

    crawler = BeautifulSoupCrawler(
        proxy_configuration=proxy_config,
        max_request_retries=3,
        max_requests_per_crawl=500,
        request_handler_timeout=30,
        session_pool=SessionPool(
            max_pool_size=20,
            create_session_timeout=10,
        ),
    )

    @crawler.router.default_handler
    async def handler(context: BeautifulSoupCrawlingContext) -> None:
        status = context.http_response.status_code
        context.log.info(
            f'Status {status} | URL: {context.request.url} '
            f'| Session: {context.session.id if context.session else "none"}'
        )

        if status == 403 or status == 429:
            # Bloqueio detectado: retira a sessão e seu IP vinculado
            if context.session:
                context.session.retire()
            context.request.retry_count += 1
            raise RuntimeError(f'Bloqueado: {status}')

        # Parsing normal
        title = context.soup.find('title')
        if title:
            await context.push_data({
                'url': context.request.url,
                'title': title.text.strip(),
            })

        # Extrai links e enfileira
        for link in context.soup.find_all('a', href=True):
            await context.enqueue_links(
                selector='a[href]',
                label='LINK',
            )

    await crawler.run(['https://example.com'])

if __name__ == '__main__':
    asyncio.run(main())

Observe os pontos-chave:

  • O ProxyHatConfiguration herda de ProxyConfiguration e sobrescreve new_url() — essa é a extensão idiomática do framework;
  • O session_id é hasheado para criar um identificador estável no ProxyHat;
  • A flag -country-US-session-abc123 no username instrui o gateway do ProxyHat a fixar o IP residencial para aquela sessão;
  • O SessionPool com max_pool_size=20 mantém até 20 IPs residenciais simultâneos;
  • O session.retire() descarta a sessão e seu IP, forçando o Crawlee a criar uma nova com um novo proxy.

Usando curl para testar o gateway

Antes de rodar o crawler, valide a conexão com curl:

curl -x http://seu_usuario-country-US-session-test123:sua_senha@gate.proxyhat.com:8080 \
  https://httpbin.org/ip

Repita a chamada com o mesmo session-test123 e você verá o mesmo IP. Mude o session ID e receberá um IP diferente.

Exemplo com PlaywrightCrawler e SOCKS5

Para sites que exigem rendering JavaScript, o PlaywrightCrawler é necessário. O ProxyHat também suporta SOCKS5:

from crawlee.playwright_crawler import PlaywrightCrawler
from crawlee.playwright_crawler import PlaywrightCrawlingContext
from crawlee.proxy_configuration import ProxyConfiguration

PROXYHAT_USER = 'seu_usuario'
PROXYHAT_PASS = 'sua_senha'

class ProxyHatSocks5Configuration(ProxyConfiguration):
    async def new_url(self, session_id: str | None = None) -> str:
        sid = session_id or 'default'
        username = f'{PROXYHAT_USER}-country-US-session-{sid}'
        return f'socks5://{username}:{PROXYHAT_PASS}@gate.proxyhat.com:1080'

async def main():
    proxy_config = ProxyHatSocks5Configuration()

    crawler = PlaywrightCrawler(
        proxy_configuration=proxy_config,
        max_request_retries=2,
        browser_type='chromium',
        headless=True,
    )

    @crawler.router.default_handler
    async def handler(context: PlaywrightCrawlingContext) -> None:
        page = context.page
        await page.wait_for_load_state('networkidle')

        # Detecta CAPTCHA do Cloudflare
        if await page.query_selector('#challenge-running'):
            if context.session:
                context.session.retire()
            raise RuntimeError('Cloudflare challenge detectado')

        title = await page.title()
        await context.push_data({'url': context.request.url, 'title': title})

    await crawler.run(['https://example.com'])

if __name__ == '__main__':
    import asyncio
    asyncio.run(main())

Padrões de produção: retry, concorrência e tratamento de erros

session.retire() no bloqueio

Quando um site retorna 403, 429, ou redireciona para uma página de CAPTCHA, você deve chamar session.retire(). Isso instrui o Crawlee a:

  1. Descartar a sessão atual (cookies, headers, IP);
  2. Criar uma nova sessão com um novo proxy do ProxyConfiguration;
  3. Fazer retry do request com a nova sessão (se retry_count < max_request_retries).

Não use session.retire() para erros transitórios como timeouts de rede ou 500s do servidor — nesses casos, apenas deixe o retry normal acontecer.

max_request_retries e backoff

O parâmetro max_request_retries controla quantas vezes um request é retentado antes de ser marcado como falha. Para crawlers com proxies residenciais:

  • max_request_retries=3 é um bom padrão;
  • Cada retry usa uma nova sessão (se a anterior foi retirada);
  • O Crawlee aplica backoff exponencial automaticamente entre retries.

Concorrência via AutoscaledPool

O AutoscaledPool do Crawlee ajusta a concorrência com base na taxa de erro. Para proxies residenciais, recomendamos:

  • min_concurrency=5 — evita overhead de warm-up;
  • max_concurrency=20 — proxies residenciais têm latência maior;
  • max_tasks_per_minute=120 — limita a taxa global.

Configurar concorrência muito alta com proxies residenciais gera mais bloqueios, não mais throughput.

Tratamento de erros no request_handler

@crawler.router.default_handler
async def handler(context: BeautifulSoupCrawlingContext) -> None:
    try:
        status = context.http_response.status_code
        
        if status in (403, 429):
            if context.session:
                context.session.retire()
            raise RuntimeError(f'Bloqueado: {status}')
        
        if status >= 500:
            # Erro do servidor: retry sem retirar sessão
            raise RuntimeError(f'Erro do servidor: {status}')
        
        # Processamento normal
        data = extract_data(context.soup)
        await context.push_data(data)
        
    except Exception as e:
        context.log.error(f'Erro em {context.request.url}: {e}')
        raise  # Re-raise para acionar retry do Crawlee

Quando NÃO usar browser crawling

Existe uma tendência a usar PlaywrightCrawler por padrão, mas isso é um erro comum. Browser crawling é 5-10x mais lento e consome muito mais recursos. Use PlaywrightCrawler apenas quando:

  • O site é uma SPA que renderiza conteúdo via JavaScript (React, Vue, Angular);
  • O site requer interação (cliques, scrolls, preenchimento de formulários);
  • O site detecta requests sem execução de JavaScript.

Para 80% dos casos de scraping de dados públicos — SERP, e-commerce, blogs, fóruns — BeautifulSoupCrawler com proxies residenciais é suficiente e significativamente mais eficiente.

Considerações éticas e legais

Antes de qualquer implementação, considere:

  • robots.txt: o Crawlee respeita robots.txt por padrão. Não desabilite isso sem motivo justificado;
  • Termos de Serviço: muitos sites proíbem scraping automático em seus ToS. Violar ToS pode ter consequências legais;
  • CFAA (EUA): o Computer Fraud and Abuse Act pode aplicar-se a acesso não autorizado a sistemas computacionais. Consulte um advogado se o alvo está nos EUA;
  • GDPR (UE): dados pessoais coletados via scraping estão sujeitos ao GDPR. Não armazene PII sem base legal;
  • Rate limits: mesmo com proxies, respeite limites razoáveis. 1-2 requests por segundo por domínio é um bom padrão;
  • APIs oficiais: se o site oferece uma API, use-a. É mais estável, legal e frequentemente mais rápida.

ProxyHat: configuração e integração

O ProxyHat oferece proxies residenciais, mobile e datacenter com gateway unificado em gate.proxyhat.com. A integração com o Crawlee é direta via ProxyConfiguration.

Parâmetros do gateway

Parâmetro Valor
Gateway gate.proxyhat.com
Porta HTTP 8080
Porta SOCKS5 1080
Geo-targeting -country-US, -country-DE-city-berlin
Sticky session -session-abc123

Consulte nossa documentação oficial para detalhes completos de autenticação e features. Para ver preços e planos, visite a página de pricing. Confira também nossos locations disponíveis em mais de 150 países.

Casos de uso

Os padrões deste guia aplicam-se diretamente a:

  • Web scraping de e-commerce para price monitoring;
  • SERP tracking para SEO e análise de concorrência;
  • Coleta de dados públicos para treinamento de modelos de IA;
  • QA automatizado de aplicações web em múltiplas geolocalizações.

Erros comuns e armadilhas

1. Rotacionar IP sem rotacionar sessão

Se você troca o proxy mas mantém a mesma sessão (cookies, User-Agent), o site detecta a inconsistência. Sempre use session.retire() ao trocar de proxy.

2. Concorrência muito alta com proxies residenciais

Proxies residenciais têm latência de 300-800ms. Configurar max_concurrency=100 gera timeouts e erros, não mais throughput. Mantenha entre 10-30.

3. Ignorar headers HTTP

O Crawlee envia headers padrão. Se todos os seus requests têm o mesmo User-Agent, o site detecta automação. Use httpx headers customizados ou o playwright_fingerprint_generator para variar.

4. Não monitorar a taxa de sucesso

Se sua taxa de sucesso cai abaixo de 90%, algo está errado — proxies ruins, concorrência muito alta, ou detecção anti-bot. Monitore via Statistics do Crawlee.

5. Usar datacenter proxies para sites protegidos

Cloudflare e DataDome bloqueiam IPs de datacenter em segundos. Não perca tempo tentando — vá direto para residenciais.

Key Takeaways

  • ProxyConfiguration é a API idiomática: herde de ProxyConfiguration e sobrescreva new_url(session_id=...) para integrar qualquer provedor de proxy.
  • Sessões sticky > round-robin: use session_id para manter o mesmo IP por sessão e preservar cookies/fingerprints.
  • Residenciais para anti-bot: proxies datacenter são detectados por Cloudflare e DataDome; residenciais têm 5-15% de taxa de bloqueio vs. 60-90%.
  • session.retire() no bloqueio: sempre retire a sessão ao receber 403/429/CAPTCHA para que o Crawlee crie uma nova com IP novo.
  • BeautifulSoupCrawler por padrão: use PlaywrightCrawler apenas quando JavaScript rendering for absolutamente necessário.
  • Ética primeiro: respeite robots.txt, ToS, CFAA/GDPR e prefira APIs oficiais quando disponíveis.

FAQ

O que é rotação de proxy no Crawlee para Python?

Rotação de proxy no Crawlee para Python é o processo de distribuir requisições HTTP entre múltiplos endereços IP usando a classe ProxyConfiguration e o SessionPool do framework. O ProxyConfiguration gera URLs de proxy por sessão ou por requisição, enquanto o SessionPool mantém cookies e fingerprints vinculados a cada IP, evitando que o site-alvo detecte padrões de acesso automatizado.

Por que a rotação de proxy no Crawlee para Python importa para usuários de proxy?

Porque sites com proteção anti-bot como Cloudflare e DataDome detectam e bloqueiam IPs de datacenter rapidamente. A rotação de proxy no Crawlee, combinada com proxies residenciais e sessões sticky, permite que cada sessão mantenha um IP residencial consistente, preservando cookies e fingerprints legítimos, o que reduz drasticamente a taxa de bloqueio em comparação com IPs de datacenter.

Qual tipo de proxy funciona melhor para rotação no Crawlee para Python?

Proxies residenciais funcionam melhor para a maioria dos casos de uso no Crawlee, pois usam IPs de ISPs reais que são difíceis de distinguir de tráfego humano. Proxies mobile são ainda mais resilientes contra bloqueios, mas mais caros. Proxies datacenter são adequados apenas para sites sem proteção anti-bot avançada. A escolha depende do nível de proteção do alvo e do orçamento.

Como evitar bloqueios ao implementar rotação de proxy no Crawlee para Python?

Use proxies residenciais com sessões sticky via ProxyConfiguration.new_url(session_id=...), chame session.retire() ao detectar bloqueios (status 403, CAPTCHAs), configure max_request_retries adequadamente, respeite robots.txt, limite a concorrência com o autoscaled pool, e implemente fallback entre tipos de proxy. Também monitore a taxa de sucesso e ajuste a concorrência dinamicamente.

Pronto para começar?

Acesse mais de 50M de IPs residenciais em mais de 148 países com filtragem por IA.

Ver preçosProxies residenciais
← Voltar ao Blog