Olhe os logs de fetch de praticamente qualquer crawler de longa duração e o mesmo padrão aparece. A grande maioria das requisições retorna uma página idêntica à última cópia. Cada um desses fetches custou banda ou créditos, ocupou um slot de concorrência e gerou carga no servidor de outra pessoa, e não produziu absolutamente nada.
Isso não é um bug no fetcher. É uma decisão de agendamento, geralmente tomada por padrão: revisitar tudo no mesmo ciclo, ou revisitar as coisas importantes com mais frequência. Ambas parecem razoáveis, e ambas desperdiçam a maior parte do orçamento. Este texto trata de tomar essa decisão de propósito, precificando cada visita pelo que ela provavelmente vai render.
Meça a unidade certa
As equipes geralmente acompanham o custo por página buscada. O número que importa é o custo por mudança detectada.
Um crawler que busca um milhão de páginas por dia e detecta dez mil mudanças gastou cem fetches por observação útil. Reduzir pela metade o número de fetches sem perder mudanças reduz pela metade o custo do dataset. Dobrar o número de fetches sem encontrar mais mudanças o dobra à toa. Coloque “fetches que não encontraram mudança” em um dashboard, por site e por tipo de página, e fica óbvio para onde vai o dinheiro.
Saiba o que um fetch realmente custa
O custo de uma visita depende de como você é cobrado, e os dois modelos comuns recompensam otimizações diferentes.
| Modelo de cobrança | Pelo que você paga | O que torna uma visita mais barata |
|---|---|---|
| Banda de proxy residencial | Bytes através do gateway | Respostas menores: sem renderização, sem imagens, transferência comprimida |
| Créditos de scraping API | Respostas bem-sucedidas | Menos fetches; o tamanho de cada um importa muito menos |
No gateway residencial da Shifter, todo byte enviado ou recebido conta, incluindo cabeçalhos, e requisições com falha contam se bytes foram transferidos antes do erro. Reduzir cada fetch traz retorno direto, e as táticas para isso estão descritas em cortando custos de banda de proxy. Na Web Scraping API, uma requisição bem-sucedida custa um crédito independentemente de a renderização de JavaScript estar habilitada ou não, e requisições com falha e erros de destino não custam nada. Ali, uma página renderizada e uma simples custam o mesmo, e a única alavanca que move a conta é quantos fetches bem-sucedidos você solicita.
De qualquer forma, o agendador é a maior alavanca que você tem, porque o fetch mais barato é aquele que você decidiu não fazer.
Com que frequência cada página muda?
Agendar por valor esperado exige uma estimativa de com que frequência cada página muda. A suposição de trabalho padrão na pesquisa sobre crawlers é que as mudanças ocorrem aproximadamente ao acaso, a uma taxa média por página, o que torna a probabilidade de uma página ter mudado desde sua última visita:
P(changed) = 1 - e^(-rate × time since last visit)
Você estima a taxa a partir do seu próprio histórico. Cada visita indica se a página mudou desde a anterior. Divida as mudanças observadas pelo tempo observado, por página, e suavize em direção à média de páginas semelhantes, para que uma página visitada três vezes não receba uma estimativa extrema.
Duas ressalvas. Primeiro, uma visita só pode informar que uma página mudou, não quantas vezes, então páginas que mudam mais rápido do que você visita parecem mais lentas do que realmente são. Segundo, defina “mudou” pelos campos que importam para você. Uma página cujo timestamp, slot de anúncio ou token de sessão difere a cada carregamento muda o tempo todo e isso não significa nada. Faça o hash do registro extraído, não do HTML.
O resultado contraintuitivo: não persiga as páginas mais rápidas
A política óbvia é visitar páginas na proporção de com que frequência elas mudam. Ela também está errada, e a prova tem mais de vinte anos.
Em “Effective Page Refresh Policies for Web Crawlers” (ACM Transactions on Database Systems, 2003), Junghoo Cho e Hector Garcia-Molina compararam políticas de alocação para manter uma cópia local atualizada com um orçamento de visitas fixo. A conclusão deles, em suas próprias palavras, é que “the uniform policy is always more effective than the proportional policy under any scenario” (a política uniforme é sempre mais eficaz que a política proporcional em qualquer cenário). A política ótima deles vai além, e eles resumem diretamente: “To improve freshness, we should penalize the elements that change too often” (para melhorar a atualidade, devemos penalizar os elementos que mudam com frequência demais).
A intuição é simples uma vez explicada. Uma página que muda a cada quinze minutos fica desatualizada de novo quase assim que você a busca. Visitá-la compra alguns minutos de atualidade. Uma página que muda cerca de uma vez por dia, visitada diariamente, permanece correta pela maior parte do dia após cada visita. Com um orçamento limitado, a segunda é uma compra muito melhor.
Dá para colocar um número nisso. Sob o mesmo modelo de mudança, a atualidade que uma visita compra é a chance de a página estar atualmente desatualizada multiplicada pelo tempo que ela provavelmente permanecerá correta depois. Para um crawler que pode revisitar cerca de uma vez por dia:
| Frequência de mudança da página | Atualidade comprada por visita (dias) |
|---|---|
| A cada 15 minutos, aproximadamente | 0,010 |
| Cerca de uma vez por hora | 0,042 |
| A cada 6 horas, aproximadamente | 0,241 |
| Cerca de uma vez por dia | 0,400 |
| Cerca de uma vez por semana | 0,124 |
| Cerca de uma vez por mês | 0,032 |
| Cerca de uma vez por ano | 0,003 |
As melhores compras são páginas que mudam mais ou menos no ritmo que você pode se dar ao luxo de revisitar. Páginas que mudam muito mais rápido são quase impossíveis de manter atualizadas a qualquer taxa acessível; páginas que mudam muito mais devagar já estão quase sempre atualizadas.
Há uma exceção importante. O resultado trata de atualidade: com que frequência sua cópia corresponde à página ao vivo. Alguns trabalhos tratam de capturar eventos em vez disso: cada mudança de preço, cada falta de estoque, cada edição. Se cada mudança importa individualmente, páginas que mudam rápido precisam de mais visitas, não menos, e a resposta certa pode ser uma fonte totalmente diferente, como uma API, um feed ou uma página de listagem que mostra a mudança sem um fetch completo. Decida qual problema você está resolvendo antes de ajustar.
Pontue cada visita pelo valor esperado por custo
Juntando as peças, cada visita candidata recebe uma prioridade: o quanto a página importa, multiplicado pela atualidade que uma visita compraria, dividido pelo que a visita custa.
import math
def freshness_gain(rate, days_since_visit, interval_days):
"""Expected fresh days bought by visiting now, under a Poisson change model."""
p_stale = 1 - math.exp(-rate * days_since_visit)
fresh_after = (1 - math.exp(-rate * interval_days)) / rate if rate > 0 else interval_days
return p_stale * fresh_after
def priority(page, today, interval_days=1.0):
gain = freshness_gain(page.change_rate, today - page.last_fetched, interval_days)
return page.value * gain / page.cost
O agendador então trabalha a partir de uma fila de prioridade: a cada ciclo, gasta o orçamento nas visitas com maior pontuação e para. Três insumos merecem atenção especial.
- Valor é um julgamento de negócio, não técnico. Um produto que vende, um concorrente que importa, uma consulta que seus clientes fazem. Mantenha isso grosseiro; três ou quatro níveis geralmente bastam.
- Custo deve ser o custo real dessa visita: bytes para aquele tipo de página, créditos, e se ela precisa de renderização. Uma página que precisa de um navegador headless em um plano cobrado por banda pode custar muitas vezes um fetch simples.
- Taxa de mudança vem do seu histórico, atualizada após cada visita.
Sinais baratos antes de fetches caros
Muitas vezes você pode descobrir se uma página mudou por muito menos do que o preço de buscá-la.
- Requisições condicionais. Onde um site honra
ETagouLast-Modified, uma resposta304 Not Modifiedcusta uma fração dos bytes. Acompanhe por host se os validadores são confiáveis; alguns sites os enviam e os ignoram. - Páginas de listagem como detectores de mudança. Uma página de categoria ou busca costuma mostrar preço e disponibilidade de dezenas de itens. Busque a listagem, compare, e busque apenas os itens cujo resumo mudou. É assim que a maioria dos feeds de preço em tempo real e monitores de estoque se mantêm acessíveis.
- Sitemaps e feeds. Onde carregam datas de modificação confiáveis, eles informam o que mudou sem visitar mais nada.
- Endpoints estruturados. Uma resposta JSON por trás de uma página costuma ser menor e mais estável do que a própria página.
Reserve orçamento para o que o agendador não consegue ver
Um agendador que só otimiza páginas conhecidas vai lentamente ficar cego. Reserve parte de cada ciclo para três coisas:
- Descoberta. URLs novas não têm histórico e nunca superariam páginas já estabelecidas. Dê a elas sua própria alocação.
- Reestimativa. Uma página classificada como imutável por meses ainda deveria ser visitada ocasionalmente, porque páginas mudam de comportamento. Sem isso, uma estimativa errada nunca é corrigida.
- Verificação. Uma pequena amostra aleatória, buscada independentemente da pontuação, informa se as suposições do modelo ainda se sustentam.
Deixe custo e saúde influenciarem o agendamento
O agendamento é um plano, não uma garantia. Quando um site começa a limitar (throttling), o agendador deveria ficar sabendo e reclassificar, em vez de continuar enfileirando visitas que a etapa de fetch não consegue realizar. Esse caminho de feedback, dos fetchers de volta para a fronteira, é abordado em backpressure e controle de fluxo em crawlers distribuídos, e a condição geral de um site em construindo um score de saúde do alvo. Um score de saúde em queda também deveria elevar o custo efetivo de visitar aquele site, que é exatamente o sinal de que um agendador sensível a custo precisa.
Conclusão
Um orçamento de crawl gasto de forma uniforme, ou na proporção de quão movimentada é cada página, é gasto principalmente confirmando que nada aconteceu. Estime com que frequência cada página muda a partir do seu próprio histórico, precifique cada visita pelo que ela vai render e pelo que vai custar, e dê o orçamento primeiro às melhores compras. Espere que essas sejam as páginas que mudam mais ou menos no ritmo que você pode se dar ao luxo de acompanhar, não as que mudam mais rápido.
O retorno não é apenas uma conta menor. Um crawler que busca menos, e busca com mais cuidado, também é mais leve para os sites dos quais depende.
Fontes e referências
- Junghoo Cho e Hector Garcia-Molina, Effective Page Refresh Policies for Web Crawlers, ACM Transactions on Database Systems, Vol. 28, No. 4, December 2003.
- Shifter, Residential Proxies bandwidth and billing. O que conta como tráfego.
- Shifter, Web Scraping API errors and limits. Custos de crédito, comportamento de falha e retentativas.