Pitch: SmartScraping: quando fazer scraping não deveria significar brigar com seletores
Se você já precisou fazer scraping de um site, provavelmente conhece o ritual:
Você abre o DevTools, procura um elemento, copia um seletor CSS, coloca no código e... pronto!
Seu scraper funciona.
Até o dia em que alguém altera o HTML da página.
Aí aquele:
document.querySelector('.product-card > div:nth-child(2) .price')
que estava funcionando perfeitamente ontem, hoje já não serve para absolutamente nada.
E foi justamente esse problema que me fez começar a desenvolver o SmartScraping.
O problema dos seletores
Quando fazemos scraping da maneira tradicional, normalmente precisamos dizer para o código onde está a informação que queremos.
Por exemplo:
{
title: 'h1',
price: '.price'
}
O problema é que estamos acoplando nosso código à estrutura daquela página.
Se o desenvolvedor do site mudar:
<h1>Produto</h1>
para:
<div class="product-title">Produto</div>
nosso scraper quebra.
E dependendo da quantidade de sites que estamos monitorando, manter todos esses seletores funcionando pode virar um trabalho considerável.
Mas e se, em vez de dizer onde está a informação, pudéssemos simplesmente dizer o que queremos?
Foi aí que começou a ideia do SmartScraping.
E se a gente simplesmente perguntasse?
A ideia é bem simples.
Você envia uma URL e define quais informações quer extrair:
"url":"https://medium.com/david-fernando/por-que-usar-typescript-ca15607eed33",
"schema": {
"title": {
"type": "string",
"description": "article title",
"maxLength": 200
},
"author": {
"type": "string",
"description": "author name"
},
"description": {
"type": "string",
"description": "article description"
},
"date": {
"type": "date",
"format": "dd/mm/yyyy"
}
}
O SmartScraping busca a página, processa o conteúdo e usa IA para identificar essas informações.
Ou seja, em vez de depender exclusivamente de:
“O preço está no .product-price.”
você pode dizer:
“Quero o preço do produto.”
E é justamente essa mudança que eu queria fazer.
Mas aí apareceu outro problema...
Usar IA para interpretar uma página parece relativamente simples.
Até você colocar uma página real na frente dela.
Uma página pode ter:
- menu;
- anúncios;
- comentários;
- rodapé;
- links;
- scripts;
- conteúdo relacionado;
- milhares de elementos que não têm absolutamente nada a ver com aquilo que você quer extrair.
Se eu simplesmente mandar o HTML inteiro para o modelo, além de aumentar bastante a quantidade de tokens, também aumento a quantidade de informação irrelevante que ele precisa analisar.
Então comecei a trabalhar no processamento do HTML antes de enviá-lo para a IA.
O SmartScraping limpa o conteúdo e remove coisas que não são relevantes para a extração.
Assim, em vez de mandar a página inteira para o modelo, tento entregar para ele somente aquilo que realmente importa.
E páginas JavaScript?
Aí apareceu outro problema.
Nem todo site entrega seu conteúdo no HTML inicial.
Existem aplicações que carregam praticamente tudo depois que o JavaScript é executado.
Se você fizer uma requisição HTTP simples, pode receber algo parecido com:
<div id="root"></div>
E boa sorte tentando extrair alguma coisa daí. 😅
Por isso o SmartScraping também possui suporte para renderização de páginas JavaScript.
No plano Pro, é possível utilizar um navegador headless para lidar com aplicações como SPAs e páginas que precisam de JavaScript para carregar o conteúdo.
Então o fluxo acaba ficando mais ou menos assim:
URL
↓
Busca da página
↓
Renderização, quando necessário
↓
Limpeza do HTML
↓
IA
↓
Dados estruturados
Só que eu ainda não estava satisfeito
Porque tinha uma parte do projeto que eu considero tão importante quanto fazer o scraping funcionar:
segurança.
Afinal, eu estava construindo uma API que recebe URLs enviadas por outras pessoas e faz requisições para essas URLs.
E isso é algo que eu definitivamente não queria tratar como:
“Depois eu vejo isso.”
Então uma parte considerável do desenvolvimento foi justamente pensando no que poderia dar errado.
E se alguém mandar uma URL maliciosa?
Antes de fazer uma requisição, o SmartScraping valida a URL.
A API não deve simplesmente receber:
https://qualquercoisa.com
e sair fazendo requisições sem verificar o destino.
Também precisei pensar em coisas como redirecionamentos, acesso a endereços que não deveriam ser acessíveis pela API e outras situações que poderiam transformar uma funcionalidade de scraping em um problema de segurança.
E as chaves da API?
Outro ponto óbvio:
A chave de API não pode ser tratada como se fosse um dado qualquer.
Ela precisa ser armazenada e utilizada de maneira que o cliente não precise expor seu segredo no frontend.
Também implementei o controle necessário para que as requisições sejam associadas ao usuário correto.
E o pagamento?
Também não queria confiar simplesmente no frontend para decidir:
“Agora esse usuário é Pro.”
Porque, obviamente, isso seria uma péssima ideia.
O pagamento é confirmado através dos eventos enviados pela Stripe para o backend.
Então existe uma separação entre:
Usuário clicou em "Upgrade"
e:
Pagamento realmente confirmado
Só depois da confirmação é que os benefícios do plano devem ser liberados.
E ainda tem o banco de dados
O SmartScraping utiliza Supabase, então também precisei tomar cuidado com quem pode acessar quais dados.
Não basta simplesmente colocar uma API funcionando e torcer para ninguém conseguir consultar informações que não deveria.
Permissões, políticas de acesso, chaves privadas e operações feitas no servidor precisam estar devidamente separadas.
Mas por que eu estou contando tudo isso?
Porque fazer o SmartScraping funcionar não foi a parte mais difícil.
Fazer:
URL → HTML → IA → JSON
é relativamente fácil de demonstrar em um projeto.
O difícil começa quando você pergunta:
“E quando alguém mandar uma URL que não deveria?”
“E se o site usar JavaScript?”
“E se o HTML mudar?”
“E se a página bloquear o scraper?”
“E se o pagamento falhar?”
“E se alguém tentar acessar dados de outro usuário?”
“E se alguma dependência externa cair?”
Essas são as perguntas que começam a aparecer quando você deixa de fazer um pequeno projeto para construir algo que outras pessoas realmente vão utilizar.
E foi aí que boa parte do meu tempo acabou sendo gasto.
Não apenas fazendo o recurso funcionar, mas pensando em como ele poderia deixar de funcionar.
No final das contas...
O SmartScraping nasceu de uma ideia relativamente simples:
Eu não queria mais depender de seletores para extrair dados da web.
Queria poder dizer:
“Me dê o nome, preço e descrição desse produto.”
e deixar a aplicação descobrir onde essas informações estão.
Ainda existe muita coisa para melhorar. Scraping não é um problema mágico que a IA consegue resolver em 100% dos casos.
Sites mudam, sistemas possuem proteções diferentes e nem todo conteúdo pode ser extraído da mesma maneira.
Mas essa é justamente a proposta do SmartScraping:
tirar do desenvolvedor uma parte da complexidade que normalmente existe entre uma página web e os dados que ele realmente queria obter.
E depois de bastante código, testes, problemas inesperados e algumas boas doses de dor de cabeça...
Ele finalmente está pronto.
Conheça o SmartScraping