Como fazer web scraping sem ser bloqueado

Publicado:

17 min de leitura

Acar Diveroli
Autor: Acar Diveroli
Um relógio de limite de taxa e um cartão de cabeçalhos alimentando um cubo scraper, seguido de um nó de rotação e um site

Um script de monitoramento de preços funciona bem no primeiro dia, devolve páginas pela metade no segundo e recebe 403 em todas as requisições no terceiro. Quase todo mundo que escreve scrapers passa por isso, e a primeira reação costuma ser procurar "mais IPs" ou "esconder melhor". A maioria dos bloqueios tem uma causa mais banal: dezenas de requisições por segundo, cabeçalhos que nunca batem com um navegador real, toda a carga concentrada em um único endereço IP e regras que o site publica abertamente e que ninguém leu.

Neste artigo, explicamos por que ferramentas de web scraping são bloqueadas, os sintomas do bloqueio e as causas por trás deles. Depois, vemos como ajustar a velocidade das requisições, manter os cabeçalhos coerentes, quando a rotação de IP é realmente necessária, como usar IP fixo onde há sessão, e o robots.txt e os termos do site. Este não é um guia para "burlar proteção": "sem ser bloqueado" significa não esbarrar em bloqueios porque você não prejudica o site e segue as regras dele.

Por que os sites bloqueiam scrapers?

Por trás de um site limitar tráfego automatizado costuma haver custos concretos, e não uma suposição de má intenção:

  • Carga no servidor. Um único script enviando centenas de requisições por segundo pode consumir os recursos que uma loja online pequena reserva para os visitantes reais. Em páginas de busca e filtro que consultam o banco de dados, o efeito se multiplica.
  • Banda e custo de infraestrutura. Cada requisição aparece na conta do servidor e da CDN do site.
  • Proteção de conteúdo e dados comerciais. Quando preços, estoque e dados de anúncios são coletados em massa por concorrentes, o dono do site pode querer restringir isso.
  • Segurança. Logins por força bruta, teste de cartões e acúmulo de estoque também são feitos com tráfego automatizado. À primeira vista, os sistemas de proteção não conseguem diferenciar esse tráfego de um scraper legítimo.

A maioria dessas decisões não é tomada no código do próprio site, e sim na camada de gerenciamento de bots na frente dele. CDNs e serviços de segurança pontuam cada requisição com sinais como velocidade, reputação do IP, coerência dos cabeçalhos e comportamento. Para um exemplo de como essa camada classifica tráfego de bots, veja Cloudflare Precursor.

Quais são os sinais de bloqueio?

Bloqueios nem sempre vêm com uma mensagem de erro clara. Se você vir um destes sintomas nos dados que o seu scraper produz, a causa provável é bloqueio:

  • 403 Forbidden: a requisição foi entendida, mas recusada. Pode ser reputação do IP, cabeçalhos ausentes ou restrição geográfica.
  • 429 Too Many Requests: você ultrapassou o limite de taxa. Muitas vezes um cabeçalho Retry-After diz quanto esperar.
  • 503 Service Unavailable: o servidor pode estar mesmo ocupado, ou um sistema de proteção de bots pode estar devolvendo essa resposta temporariamente.
  • 200, mas com página de verificação: o código de status parece de sucesso, mas o conteúdo é uma tela de verificação em vez da lista de produtos.
  • 200, mas com conteúdo vazio ou incompleto: os seus seletores não encontram nada. Pode ser bloqueio ou uma página que carrega o conteúdo com JavaScript.
  • Redirecionamento para a página de login: a sua sessão foi encerrada, muitas vezes por uma troca de IP no meio da sessão.
  • Respostas cada vez mais lentas: alguns sistemas atrasam a resposta de propósito em vez de recusar a requisição.

Explicamos cada código de status HTTP e quais vale a pena tentar de novo em Códigos de status HTTP no web scraping. Para saber se um conteúdo vazio é bloqueio ou página dinâmica, veja Páginas estáticas e dinâmicas.

SintomaCausa provávelSolução legítima
Muitos 429 em pouco tempoA taxa de requisições ultrapassa o limite do siteReduzir a concorrência, esperar o que o Retry-After indicar
403 já na primeira requisiçãoCabeçalhos ausentes, IP de datacenter ou restrição regionalUsar cabeçalhos coerentes; escolher tipo de IP e localização que combinem com o público do site
403 que começa depois de um tempoO tráfego intenso de um único IP foi marcadoIr mais devagar e distribuir a carga no tempo e, se preciso, entre IPs
Página de verificaçãoComportamento ou reputação do IP considerados suspeitosParar, revisar velocidade e escopo; buscar uma API ou permissão
200, mas conteúdo vazioA página carrega com JavaScript ou o conteúdo foi escondidoEncontrar a requisição de API em segundo plano; um navegador headless se necessário
A sessão cai de repenteO IP mudou no meio da sessãoUsar IP fixo durante a sessão
As respostas ficam lentas com o tempoCarga no servidor ou atraso propositalReduzir a velocidade, evitar horários de pico
O conteúdo difere do navegador realConteúdo específico para bots ou diferença de localizaçãoConferir a localização; usar uma identidade de cliente que apresente você

Velocidade das requisições: como respeitar os limites?

A causa de bloqueio mais comum e mais fácil de evitar é a velocidade. Uma pessoa em uma loja online abre uma página a cada poucos segundos; um scraper escrito com asyncio pode enviar centenas de requisições no mesmo tempo. A RFC 6585 define o código 429 Too Many Requests exatamente para essa situação e diz que o servidor pode informar quanto esperar com um cabeçalho Retry-After.

As regras básicas para manter a velocidade sob controle:

  1. Defina um limite de concorrência por site. Mantenha pequeno o número de requisições abertas para o mesmo domínio. A concorrência total pode ser alta, mas a fatia de um único site deve ser baixa.
  2. Adicione pausas aleatórias entre as requisições. Uma requisição a cada 2 segundos exatos chama mais atenção do que intervalos irregulares e não evita picos momentâneos.
  3. Ao receber 429 e 503, desacelere, não acelere. Reenviar na hora uma requisição que falhou piora o problema. Use backoff exponencial.
  4. Respeite o cabeçalho Retry-After. O valor pode ser um número de segundos ou uma data HTTP; a explicação do MDN mostra as duas formas.
  5. Não envie requisições desnecessárias. Para não baixar de novo páginas que não mudaram, guarde os valores de ETag e Last-Modified e envie requisições condicionais com If-None-Match e If-Modified-Since; se a página não mudou, o servidor retorna 304 sem corpo.
  6. Use o sitemap. Comece pelos endereços do sitemap.xml do site em vez de rastrear o site inteiro link por link.
  7. Evite horários de pico. Não faça coleta em massa quando o público do site está mais ativo.

A função Python abaixo respeita o cabeçalho Retry-After nas respostas 429, 502, 503 e 504; quando não há cabeçalho, aplica backoff exponencial com um componente aleatório. Ela não tenta de novo respostas como 403 e 404, porque reenviar não muda o resultado:

python
import random
import time
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime

import requests

RETRY_STATUS = {429, 502, 503, 504}


def retry_after_seconds(value):
    """Retry-After pode ser segundos ou uma data HTTP."""
    if not value:
        return None
    if value.isdigit():
        return int(value)
    try:
        when = parsedate_to_datetime(value)
    except (TypeError, ValueError):
        return None
    return max(0.0, (when - datetime.now(timezone.utc)).total_seconds())


def polite_get(session, url, max_attempts=5, base=1.0, cap=60.0):
    for attempt in range(max_attempts):
        try:
            response = session.get(url, timeout=20)
        except (requests.ConnectionError, requests.Timeout):
            response = None

        if response is not None and response.status_code not in RETRY_STATUS:
            return response  # respostas como 200, 404 e 403 não são tentadas de novo

        wait = None
        if response is not None:
            wait = retry_after_seconds(response.headers.get("Retry-After"))
        if wait is None:
            wait = min(cap, base * 2**attempt) * random.uniform(0.5, 1.0)
        time.sleep(min(wait, cap))

    raise RuntimeError(f"{url}: sem resposta após {max_attempts} tentativas")

Basta usar essa função em uma lista de páginas com uma pausa entre as requisições:

python
session = requests.Session()
session.headers.update({
    "User-Agent": "ExamplePriceBot/1.0 (+https://example.com/about-our-bot)",
    "Accept-Language": "pt-BR,pt;q=0.9",
})

for url in urls:
    response = polite_get(session, url)
    if response.status_code == 403:
        print("Acesso negado, pare e investigue:", url)
        break
    process(response.text)
    time.sleep(random.uniform(2, 5))

Como ajustar a concorrência e o que realmente limita a velocidade está em Concorrência e paralelismo.

Cabeçalhos e uma identidade de cliente coerente

Os cabeçalhos de uma requisição HTTP dizem quem é o cliente e o que ele aceita. Os cabeçalhos padrão das bibliotecas são muito diferentes dos de um navegador. O Python Requests envia por padrão um User-Agent como python-requests/2.x; muitos sites rejeitam esse valor direto.

Há duas abordagens aqui, e elas servem a propósitos diferentes:

Apresentar-se. Crawlers legítimos colocam no User-Agent o nome do bot e um endereço com informações sobre ele: ExamplePriceBot/1.0 (+https://example.com/about-our-bot). Quando o administrador do site vê o tráfego, sabe quem está enviando e como falar com você; se houver problema, pode entrar em contato em vez de bloquear. Também pode escrever regras de robots.txt específicas para esse nome.

Coerência. Qualquer que seja a identidade usada, ela precisa ser coerente em toda a requisição. Exemplos de incoerência:

  • Um User-Agent que muda aleatoriamente a cada requisição, mas com os mesmos cookies e o mesmo IP.
  • Um User-Agent que diz ser Chrome, mas sem nenhum dos cabeçalhos Accept, Accept-Language e Sec-CH-UA que o Chrome envia em toda requisição.
  • Acessar um site de Türkiye com Accept-Language: en-US e um IP saindo nos EUA esperando preços em lira turca.

Explicamos quais sinais, além dos cabeçalhos, identificam navegadores em Browser fingerprinting. Falsificar esses sinais para burlar a proteção de bots não é o que este artigo recomenda; o objetivo é que o seu cliente diga de forma coerente o que ele é.

Diversidade de IP: quando a rotação é necessária?

Tráfego intenso de um único endereço IP é a unidade em que é mais fácil aplicar limites de taxa. Por isso "fui bloqueado, vou trocar de IP" é um reflexo tão comum. Mas a rotação tem dois propósitos legítimos e um uso errado.

Propósito legítimo 1: distribuir a carga. Um trabalho que coleta páginas públicas de preço em centenas de sites diferentes, mandando todo o tráfego de um único IP, dá rapidamente má reputação a esse IP e pode fazer com que ele seja marcado em listas gerais de reputação, mesmo sem ultrapassar o limite de nenhum site específico. Distribuir o tráfego entre endereços diferentes mantém a carga de cada endereço em um nível realista.

Propósito legítimo 2: ver conteúdo por localização. Preços, estoque e resultados de busca mudam conforme o país e a cidade do visitante. Sair de localizações diferentes é o único jeito de coletar a visão real de cada mercado.

Uso errado: contornar um bloqueio explícito. Se o site avisou com um limite de taxa, fechou aquele caminho no robots.txt ou proíbe expressamente o acesso automatizado nos termos, trocar de IP e continuar na mesma velocidade não resolve nada; significa ignorar uma preferência que o dono do site deixou clara.

A rotação pode ser montada com um Proxies rotativos, que dá um IP de saída diferente a cada conexão por um único endereço. Para trabalhos que precisam de endereços de conexões domésticas reais, prefere-se um Proxies residenciais. Mostramos uma configuração rotativa em Python em Como rotacionar proxies em Python.

IP fixo onde há sessão

Trocar de IP a cada requisição não serve para todo trabalho. Nestes, o endereço IP precisa ficar fixo por um tempo:

  • Páginas logadas. Se você extrai relatórios do painel da sua própria conta, uma troca de IP no meio da sessão dispara verificações de segurança e a sessão cai.
  • Fluxos de várias etapas. Fluxos que guardam estado no servidor, como adicionar ao carrinho, escolher filtros ou paginar.
  • Visitas ligadas a cookies. Requisições com o mesmo cookie vindas de países diferentes criam uma imagem de visitante incoerente.

Para esses trabalhos, um Proxies de sessão fixa mantém o mesmo IP de saída por um período definido. A regra geral: uma sessão = um IP; o IP pode mudar quando a sessão termina.

robots.txt e termos do site

Antes de coletar dados de um site, dois documentos devem ser conferidos.

O robots.txt é o arquivo em que um site diz quais caminhos não quer que os bots rastreiem, e o formato dele é padronizado na RFC 9309. Não rastrear os caminhos fechados com Disallow é respeitar a preferência que o site declarou explicitamente. Explicamos como ler o arquivo e verificá-lo com Python em O que é robots.txt e como ler o arquivo?.

Os termos de uso podem ter cláusulas sobre acesso automatizado. Alguns sites proíbem scraping por completo, outros limitam a uma certa velocidade e outros oferecem uma API oficial para os dados. Se houver API oficial, ela é quase sempre o caminho mais sólido: os dados chegam estruturados, o seu código não quebra quando o design da página muda e o seu acesso se baseia em um acordo.

Páginas com dados pessoais exigem cuidado extra; as obrigações da KVKK em Türkiye e do GDPR na Europa valem independentemente de como você coleta os dados. Tratamos do enquadramento legal em Web scraping é legal?.

Alguns sites também colocam links escondidos que os visitantes não veem, mas nos quais os bots caem. Um crawler que segue links visíveis e mantém o escopo restrito fica naturalmente longe dessas armadilhas; explicamos o mecanismo em Armadilhas honeypot.

O que fazer quando aparece um CAPTCHA?

Uma tela de verificação na frente de um scraper significa que o site considera o seu tráfego suspeito. Nesse ponto, serviços de resolução de CAPTCHA ou plugins de evasão de detecção não são recomendados; eles significam tentar burlar um controle explícito do site e geralmente escondem a origem do problema. Em vez disso, siga esta ordem:

  1. Pare o scraper. Continuar enviando requisições para a tela de verificação derruba ainda mais a reputação do IP e da sessão.
  2. Meça a velocidade. Confira quantas requisições você enviou ao mesmo site no último minuto.
  3. Compare os cabeçalhos com um navegador real. Falta algum cabeçalho, ou há algum contraditório?
  4. Revise o escopo. Você está rastreando caminhos fechados pelo robots.txt ou páginas de que não precisa?
  5. Procure alternativas. Uma API oficial, uma opção de exportação de dados ou o contato direto com o dono do site.
  6. Só então tente de novo em velocidade menor, com uma identidade de cliente coerente.

Explicamos por que telas de verificação aparecem na automação de navegador, com a mesma lógica de diagnóstico, em Puppeteer e CAPTCHA.

O que fazer quando for bloqueado: lista de diagnóstico

  • Você sabe quando o bloqueio começou e qual era a taxa de requisições nesse momento?
  • Qual é o código de resposta: 403, 429, 503 ou 200 com página de verificação?
  • Veio um cabeçalho Retry-After, e você o respeitou?
  • O mesmo endereço abre em um navegador real com o mesmo IP?
  • Os seus cabeçalhos são coerentes, ou o User-Agent é o padrão da biblioteca?
  • Os caminhos que você rastreia estão fechados no robots.txt?
  • O que os termos do site dizem sobre acesso automatizado?
  • O IP muda em um fluxo que precisa de sessão?
  • O conteúdo vazio vem de uma página que carrega com JavaScript?
  • Existe uma API oficial que forneça os mesmos dados?

Casos de uso

  • Monitoramento de preços: algumas vezes por dia, endereços de produto tirados do sitemap, só as páginas que mudaram via requisições condicionais. A configuração está na nossa página de solução de monitoramento de preços.
  • Pesquisa de mercado e coleta de catálogos: páginas públicas de muitos sites diferentes, concorrência baixa por site e rotação para distribuir a carga. A configuração geral está na nossa página de solução de extração de dados.
  • Rastreamento amplo: um crawler que segue links, respeita o robots.txt e mantém uma fila por domínio. O lado da escala está na nossa página de solução de web crawler.
  • Acompanhar resultados de busca por localização: primeiro a API oficial, depois pontos de saída por cidade. Os detalhes estão em Como automatizar o acompanhamento de posições no SEO.
  • Seletores robustos: mesmo sem bloqueio, os dados voltam vazios quando a estrutura da página muda. Explicamos como escrever seletores que não quebram em Seletor CSS ou XPath.

Erros comuns

  • Iniciar centenas de requisições de uma vez com Promise.all ou asyncio.gather. A velocidade total parece alta, mas a carga em cada site fica inaceitável.
  • Tentar de novo imediatamente ao receber 429. Novas tentativas sem backoff prolongam o limite de taxa.
  • Usar o User-Agent padrão da biblioteca. Muitos sites bloqueiam esse valor direto.
  • Gerar um User-Agent aleatório a cada requisição. Uma identidade que muda com o mesmo IP e os mesmos cookies é sinal de incoerência.
  • Trocar de IP a cada requisição em um trabalho que precisa de sessão. A sessão cai e você é redirecionado para a página de login.
  • Confundir código de status de sucesso com dados certos. Uma página de verificação devolvida com 200 gera dados quebrados em silêncio, porque os seletores voltam vazios. Confira se um elemento esperado existe no conteúdo da resposta.
  • Não ler o robots.txt. Rastrear sem conhecer a preferência do site é um começo fraco, tanto ético quanto legal.

Guia de decisão

Sua situaçãoRecomendação
Existe API oficialA API primeiro
Poucas páginas de um único siteUm único IP, velocidade baixa, cabeçalhos coerentes
Páginas públicas de muitos sitesConcorrência baixa por site + proxy rotativo
Conteúdo de outro país ou cidadeProxy residencial com escolha de localização
A sua própria conta logadaIP sticky ou fixo, o mesmo endereço durante a sessão
Você está recebendo 429Espere o que o Retry-After indicar, reduza a concorrência
Apareceu uma tela de verificaçãoPare, siga a lista de diagnóstico, procure alternativas
A página volta vaziaConfira primeiro se ela carrega de forma dinâmica
O caminho está fechado no robots.txtNão rastreie

Perguntas frequentes

Usar proxy evita bloqueios por completo?

Não. O proxy distribui o tráfego entre endereços IP diferentes e permite ver conteúdo por localização, mas requisições enviadas rápido demais, com cabeçalhos incoerentes ou para caminhos que o site fechou são bloqueadas venham do IP que vierem. O proxy funciona junto com a velocidade certa e um cliente coerente.

Quantas requisições por segundo são seguras?

Não existe um valor seguro único para todos os sites; depende da infraestrutura do site, do peso da página e do horário. Se o robots.txt indicar um Crawl-delay, respeite. Se não, comece com uma taxa baixa, aumente devagar observando os 429 e os tempos de resposta e recue assim que perceber o servidor ficando lento.

O User-Agent deve ser de navegador ou um nome de bot?

Para um crawler legítimo, o recomendado é escrever o nome do seu bot e um endereço de contato. O administrador do site vê quem você é e pode falar com você se houver problema. Alguns sites bloqueiam bots desconhecidos por padrão; nesse caso, pedir permissão ou procurar uma API oficial é um caminho mais sólido do que tentar parecer um navegador.

Usar navegador headless reduz o risco de bloqueio?

Ele permite ver dados em páginas que carregam com JavaScript, mas sozinho não reduz o risco de bloqueio. Pelo contrário: cada página gera dezenas de requisições extras (imagens, scripts, folhas de estilo) e coloca mais carga no site. Encontrar a requisição de API que a página faz em segundo plano geralmente é mais eficiente.

O meu IP foi bloqueado. Quanto tempo vai durar?

Varia conforme o site: de um limite de taxa de alguns minutos a uma lista negra de dias. Se houver cabeçalho Retry-After, ele informa a duração. Se não, espere um pouco e envie uma única requisição em velocidade bem baixa para verificar; não continue na mesma velocidade antes de o bloqueio sair.

Preciso de todos esses cuidados para um trabalho pequeno e pontual?

Para um trabalho pontual de algumas dezenas de páginas, colocar alguns segundos entre as requisições, usar um User-Agent com sentido e conferir o robots.txt geralmente basta. Os outros cuidados passam a importar quando o trabalho fica regular e em grande escala.

Em resumo

A maioria dos scrapers não é bloqueada por não saber se esconder, e sim por sobrecarregar o site e parecer incoerente. Limite a velocidade das requisições por site, respeite as respostas 429 e o Retry-After, não baixe de novo páginas que não mudaram, use uma identidade de cliente coerente que apresente você e leia o robots.txt e os termos do site. A rotação de IP serve para distribuir carga e ver conteúdo por localização, e o IP sticky, para trabalhos que precisam de sessão; nenhum dos dois é ferramenta para contornar um bloqueio explícito. Tipos de proxy adequados ao seu trabalho de coleta de dados estão nos nossos serviços de proxy.