Como um Crawler Web Funciona
Toda vez que voce pesquisa algo no Google, os resultados vem de um indice gigantesco construido por crawlers — programas que navegam automaticamente pela web lendo e catalogando paginas. Mas como eles funcionam por baixo dos panos?
O que e um Crawler?
Um web crawler (tambem chamado de spider ou bot) e um programa que:
- Comeca com uma lista de URLs iniciais (seed URLs)
- Faz o download do HTML de cada pagina
- Extrai todos os links encontrados naquela pagina
- Adiciona os novos links a uma fila para visitar depois
- Repete o processo indefinidamente
O resultado e um mapa da web — ou de uma parte dela.
A Estrutura Basica
[Fila de URLs] --> [Fetcher] --> [HTML cru]
|
[Parser/Extrator]
|
+------------+------------+
| |
[Novos links] [Dados extraidos]
| |
[Fila de URLs] [Banco de dados / Indice]
Componentes principais
| Componente | Responsabilidade |
|---|---|
| Scheduler | Decide qual URL visitar a seguir e quando |
| Fetcher | Faz requisicoes HTTP e baixa o HTML |
| Parser | Extrai links e dados do HTML |
| Storage | Armazena paginas, links e metadados |
| Deduplicator | Evita visitar a mesma URL duas vezes |
Algoritmos de Navegacao
Breadth-First Search (BFS)
O algoritmo mais comum. O crawler visita todas as paginas de um nivel antes de descer para o proximo.
Pagina raiz
├── Link A ← visita primeiro
├── Link B ← visita segundo
└── Link C ← visita terceiro
└── Link D ← visita depois de A, B e C
Vantagem: descobre paginas populares rapidamente (elas tendem a ter muitos links apontando para elas).
Priority Queue (BFS ponderado)
Em vez de uma fila simples, usa-se uma fila de prioridade baseada em heurísticas:
- PageRank estimado: paginas com mais links entrada tem prioridade
- Frescor: paginas atualizadas frequentemente sao visitadas mais cedo
- Profundidade: evitar descer muito fundo na arvore de links
Implementacao Simples em Node.js
import { JSDOM } from 'jsdom';
class Crawler {
constructor(seedUrls, maxPages = 100) {
this.queue = [...seedUrls];
this.visited = new Set();
this.maxPages = maxPages;
this.results = [];
}
async fetchPage(url) {
const response = await fetch(url, {
headers: { 'User-Agent': 'MyCrawler/1.0' },
signal: AbortSignal.timeout(10_000),
});
return response.text();
}
extractLinks(html, baseUrl) {
const dom = new JSDOM(html, { url: baseUrl });
const anchors = dom.window.document.querySelectorAll('a[href]');
return [...anchors]
.map((a) => a.href)
.filter((href) => href.startsWith('http'));
}
async crawl() {
while (this.queue.length > 0 && this.results.length < this.maxPages) {
const url = this.queue.shift();
if (this.visited.has(url)) continue;
this.visited.add(url);
try {
console.log(`Crawling: ${url}`);
const html = await this.fetchPage(url);
const links = this.extractLinks(html, url);
this.results.push({ url, linksFound: links.length });
// Adiciona links novos a fila
for (const link of links) {
if (!this.visited.has(link)) {
this.queue.push(link);
}
}
} catch (err) {
console.error(`Erro em ${url}: ${err.message}`);
}
}
return this.results;
}
}
// Uso
const crawler = new Crawler(['https://example.com'], 50);
const results = await crawler.crawl();
console.log(`Paginas visitadas: ${results.length}`);
Desafios do Mundo Real
1. Robots.txt
Todo crawler respeitoso verifica o arquivo robots.txt antes de acessar um site:
# robots.txt de example.com
User-agent: *
Disallow: /admin/
Disallow: /private/
Crawl-delay: 1
O campo Crawl-delay e especialmente importante — ignorá-lo pode sobrecarregar o servidor alvo e resultar em banimento de IP.
2. Rate Limiting
Crawlers educados adicionam um delay entre requisicoes e respeitam os limites do servidor. Uma boa pratica e usar uma fila com controle de concorrencia:
// Maximo 5 requisicoes simultaneas
const CONCURRENCY = 5;
const delay = (ms) => new Promise((r) => setTimeout(r, ms));
async function crawlWithLimit(urls) {
const chunks = [];
for (let i = 0; i < urls.length; i += CONCURRENCY) {
chunks.push(urls.slice(i, i + CONCURRENCY));
}
for (const chunk of chunks) {
await Promise.all(chunk.map(fetchPage));
await delay(1000); // 1s entre lotes
}
}
3. JavaScript Rendering
Sites modernos usam SPAs (Single Page Applications) onde o conteudo e renderizado pelo JavaScript. Um crawler simples que so baixa HTML nao consegue ver esse conteudo.
A solucao e usar um headless browser como o Playwright:
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.waitForLoadState('networkidle'); // Espera o JS terminar
const html = await page.content(); // HTML depois do JS
const links = await page.$$eval('a', (as) => as.map((a) => a.href));
await browser.close();
4. Deduplicacao de Conteudo
A mesma pagina pode ter URLs diferentes:
https://example.com/post
https://example.com/post/
https://example.com/post?utm_source=twitter
A solucao e normalizar as URLs (remover query strings de tracking, trailing slashes) e usar hashing do conteudo para detectar duplicatas.
Crawlers no Mundo Real
| Crawler | Empresa | Proposito |
|---|---|---|
| Googlebot | Indexar a web para busca | |
| Bingbot | Microsoft | Indexar para o Bing |
| CCBot | Common Crawl | Dataset publico para pesquisa |
| AhrefsBot | Ahrefs | Analise de SEO e backlinks |
Escala do Googlebot
Para dar uma ideia de escala: o Google processa centenas de bilhoes de paginas. Para isso, o Googlebot:
- Roda em milhares de maquinas em paralelo
- Prioriza paginas com base em PageRank e frescor
- Armazena paginas em um sistema distribuido (Bigtable)
- Repassa o conteudo para o indexador, que constroi o indice invertido
Construindo um Crawler Etico
Alguns principios essenciais:
- Respeite o robots.txt — sempre
- Identifique-se no User-Agent (ex:
MeuCrawler/1.0 (+https://meusite.com)) - Limite a taxa de requisicoes — nao sobrecarregue servidores
- Armazene apenas o necessario — nao guarde dados que nao precisa
- Nao crawle dados pessoais sem consentimento explicito
Conclusao
Um crawler e, no fundo, um grafo sendo explorado em BFS. A complexidade vem dos detalhes: gerenciar escala, lidar com JavaScript, respeitar limites e deduplicar conteudo.
Se voce quer experimentar, comece pequeno: crawle apenas seu proprio site com o codigo Node.js acima. E um otimo exercicio para entender redes, parsing de HTML e algoritmos de grafos na pratica.
Ficou com alguma duvida? Deixe nos comentarios abaixo!