Abra uma página web moderna, observe a atividade de rede, e você frequentemente verá os dados que deseja chegarem como JSON antes da página desenhá-los. Os preços, listagens ou resultados que um scraper extrairia laboriosamente do HTML estão numa resposta limpa e estruturada que a própria página buscou.
Coletar a partir dessa resposta em vez da página renderizada pode ser menor, mais estável e muito mais fácil de analisar. Mas não é tão simples quanto copiar uma URL, e duas coisas surpreendem a maioria das equipes: quão pouco do JSON de uma página é realmente dado, e com que frequência o endpoint de dados se recusa a funcionar fora da página que o chamou. Este guia mostra como encontrar o endpoint certo, o que medimos em páginas reais, e como coletar dele sem ultrapassar limites.
Principais conclusões
- A maior parte do JSON que uma página carrega não é dado. Na página de busca de voos de uma companhia aérea, as tarifas vieram em uma única resposta de 44.9 KB, cerca de 8% do JSON da página e cerca de 1.2% de seus 3.6 MB de transferência total.
- Algumas páginas não têm API de dados alguma. Na página de previsão de um serviço nacional de meteorologia, toda resposta JSON pertencia à ferramenta de consentimento de cookies, e a previsão estava no HTML.
- Encontre o endpoint pesquisando os corpos das respostas por um valor que você pode ver na página, não adivinhando a partir de URLs.
- APIs de página frequentemente estão vinculadas à sessão da página. O endpoint de tarifas da companhia aérea funcionava dentro da página e retornava um HTTP 409 quando chamado diretamente.
- Use apenas endpoints públicos que a página chama para visitantes anônimos, no ritmo em que uma pessoa navegando o faria, e prefira uma API oficial sempre que houver uma.
O que medimos
Carregamos duas páginas públicas em um navegador real em 30 de setembro de 2026 e registramos cada resposta.
| Busca de voos de companhia aérea | Previsão do tempo | |
|---|---|---|
| Requisições | 61 | 46 |
| Total transferido | 3.62 MB | 2.57 MB |
| Respostas JSON | 15, 534 KB | 3, 1.04 MB |
| Respostas JSON contendo os dados | 1, 44.9 KB | 0 |
| Onde os dados estavam | Um endpoint de tarifas | O HTML renderizado no servidor |
Na página da companhia aérea, as maiores respostas JSON não eram tarifas de forma alguma. Um serviço de feature-flag de terceiros retornou a mesma resposta de 97 KB quatro vezes, e um pacote de tradução adicionou outros 92 KB. As tarifas chegaram em uma única resposta da própria API de reservas da companhia aérea.
Na página de meteorologia, todas as três respostas JSON vieram da ferramenta de gerenciamento de consentimento, uma delas uma lista de fornecedores de 860 KB, enquanto a própria previsão foi renderizada no HTML no servidor. “Coletar do JSON” não teria coletado nada útil.
Encontrando o endpoint que carrega os dados
O método confiável é pesquisar, não adivinhar. Escolha um valor que você pode ver na página, como um preço, um nome de produto ou um identificador, carregue a página em um navegador real, e encontre qual resposta JSON o contém.
Manualmente, isso é feito com as ferramentas de desenvolvedor do navegador: abra a aba Network, filtre para Fetch/XHR, recarregue, e pesquise os corpos das respostas pelo valor. De forma automatizada, é um script curto:
import { chromium } from 'playwright';
// Load a page once and report which JSON responses contain a value you can see on it.
export async function findEndpoint(url, needle, waitMs = 20000) {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
const hits = [];
page.on('response', async (response) => {
const type = response.request().resourceType();
const contentType = response.headers()['content-type'] || '';
if (!['xhr', 'fetch'].includes(type) || !contentType.includes('json')) return;
try {
const body = await response.text();
if (body.includes(needle)) {
hits.push({
method: response.request().method(),
status: response.status(),
bytes: Buffer.byteLength(body),
url: response.url(),
});
}
} catch {
// Some responses (redirects, aborted requests) have no readable body.
}
});
// Analytics beacons keep many pages from ever going network-idle,
// so wait for the DOM, then until a match appears or the time runs out.
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 90000 });
for (let waited = 0; waited < waitMs && hits.length === 0; waited += 500) {
await page.waitForTimeout(500);
}
await page.waitForTimeout(1000);
await browser.close();
return hits;
}
Dada a página de voos da companhia aérea e uma tarifa visível nela, o script retornou exatamente uma correspondência entre 61 requisições: a resposta de disponibilidade da API de reservas. Observe a estratégia de espera. Nossa primeira versão esperava a página ficar ociosa na rede, o que nunca aconteceu, porque beacons de analytics continuavam disparando; ela expirou após 90 segundos. Esperar pelo DOM e depois por uma correspondência é mais confiável.
É possível chamá-lo diretamente?
Frequentemente não. Quando solicitamos o mesmo endpoint de disponibilidade da companhia aérea diretamente, sem a página, ele retornou HTTP 409 para requisições de seis países diferentes igualmente, enquanto a própria página o carregava sem problemas. APIs de página comumente dependem de coisas que a página configura primeiro: cookies de sessão, tokens embutidos no HTML, cabeçalhos de requisição, ou uma sequência de chamadas anteriores.
Isso deixa duas abordagens:
- Deixe a página fazer a chamada. Carregue a página em um navegador e leia a resposta JSON conforme ela chega, como o script acima faz. Você obtém os dados limpos sem reconstruir a sessão, ao custo de executar um navegador.
- Reproduza apenas endpoints simples e públicos. Alguns endpoints não precisam de nada além de uma URL. A mesma companhia aérea também publica um endpoint de tarifas público que responde a requisições simples, que usamos em um teste separado sobre se os preços mudam por país de saída. Onde um endpoint funciona de forma tão simples, é de longe a opção mais barata.
O que não se deve fazer é contornar a sessão: coletar tokens, forjar cabeçalhos ou reproduzir chamadas autenticadas para alcançar dados que o site não disponibilizou a visitantes anônimos. É aí que a coleta deixa de ser observação.
Por que o JSON vale a pena quando está disponível
Quando os dados de fato chegam como JSON, os ganhos são reais:
- Tamanho. A resposta de tarifas tinha 44.9 KB contra 3.6 MB da página completa. Em coleta cobrada por largura de banda, essa diferença é a maior parte da conta, como mostra custo por registro limpo.
- Estrutura. Os campos chegam nomeados e tipados, sem seletores para escrever ou manter.
- Completude. As respostas frequentemente carregam mais do que a página exibe, como identificadores, todas as classes de tarifa ou sinalizadores de estoque.
As contrapartidas são igualmente reais. Endpoints não documentados mudam sem aviso, e uma resposta que muda de forma quebra seu parser silenciosamente, que é exatamente o problema para o qual existe o monitoramento de schema drift. Um número de versão no caminho, como o v4 na API de reservas da companhia aérea, é um sinal leve de estabilidade, não uma promessa.
Onde isso se encaixa entre as alternativas
| Fonte | Estabilidade | Esforço | Use quando |
|---|---|---|---|
| API oficial e documentada | Mais alta | Mais baixo | Sempre verifique primeiro |
| JSON-LD ou estado de página embutido | Alta | Baixo | A página o publica, veja pare de analisar HTML |
| Endpoints JSON próprios da página | Média | Média | Os dados carregam depois da página, e o endpoint é público |
| HTML renderizado e seletores | Mais baixa | Mais alto | Nada mais carrega os dados |
| Um modelo lendo a página | Varia | Baixo por site, alto por página | Muitos templates, como em extração por LLM vs seletores |
Colete de forma responsável
Os endpoints que uma página chama fazem parte do site, e as regras do site ainda se aplicam. Use apenas endpoints que a página chama para visitantes anônimos, ajuste o ritmo das requisições como uma pessoa navegando faria, respeite o robots.txt e os termos do site, e deixe de lado qualquer coisa atrás de um login ou token, a menos que você tenha permissão. Onde um site oferece uma API oficial, use-a; ela é mais estável, e é o que o site concordou em suportar. Os princípios mais amplos estão em robots.txt, opt-outs de IA e sinais de reserva.
Conclusão
Os dados por trás de uma página moderna frequentemente chegam como JSON, e quando isso acontece, coletá-los ali é menor, mais limpo e mais fácil de manter do que analisar HTML. Mas encontrá-lo exige uma pesquisa, não um palpite: nas páginas que medimos, o JSON útil era uma resposta entre muitas, e em uma página ele simplesmente não existia.
Pesquise os corpos das respostas por um valor que você pode ver, verifique se o endpoint funciona sozinho, deixe a página fazer a chamada quando não funcionar, e permaneça dentro do que o site oferece a qualquer visitante anônimo.
Fontes e referências
- Páginas carregadas e medidas pela Shifter em 30 de setembro de 2026, usando o código acima.
- Playwright, documentação de eventos de rede.