O parser puxa 400 KB de HTML para obter oito campos que o site fornece a si mesmo na resposta JSON de 8 KB. A diferença de cinquenta vezes não se trata de "código bonito", mas sim da conta por proxies residenciais, onde você paga por cada gigabyte. Vamos analisar como encontrar a API interna do site, o que impede sua replicação em 2026 e quando é melhor desistir dessa ideia.
Por que procurar uma API oculta, se o HTML já está sendo analisado
Quase qualquer interface moderna — React, Vue, Angular, Next.js — primeiro carrega a estrutura da página e depois puxa os dados através de solicitações separadas para seus próprios endpoints. Esses endpoints não são documentados, mas existem, respondem com JSON puro e estão acessíveis sem um navegador headless.
O que você ganha ao acessá-los:
- O tráfego cai drasticamente. Ao analisar uma página típica de produtos, a página HTML pesa cerca de 400 KB, incluindo marcação, estilos e rastreadores, enquanto o endpoint JSON correspondente pesa cerca de 8 KB, e contém mais campos: IDs internos, estoques, variantes de produtos.
- Não é necessário um navegador. O renderização de JavaScript é eliminada, assim como a memória, o processador e dezenas de solicitações adicionais por fontes e análises.
- Os dados já estão estruturados. Sem seletores que quebram com a mudança de classes CSS.
- Menos solicitações — menos motivos para banimento. Renderizar uma única página de catálogo em um navegador envolve dezenas de acessos ao site; a mesma quantidade de dados via API — uma única solicitação.
Para um projeto com proxies residenciais, isso representa uma economia direta: a tarifa é calculada por gigabytes, e a transição de renderização para JSON geralmente reduz a conta mais do que qualquer artifício para bloquear imagens. Um tema relacionado é como reduzir o tráfego do parser em 5 vezes com outros métodos.
Passo a passo: como encontrar o endpoint
- Primeiro, verifique se há uma API oficial. Dê uma olhada em
/developers,/api,/docsdo site alvo. Uma API pública documentada possui versionamento e avisa sobre desativações — a privada muda em silêncio. - Abra o DevTools (F12) e vá para a aba Network, certificando-se de que a gravação está ativada.
- Ative o filtro Fetch/XHR. Ele filtra imagens, fontes e análises, deixando apenas as solicitações por dados.
- Limpe a lista para remover o ruído da carga inicial.
- Provocar os dados necessários: role pela lista, clique em "próxima página", aplique um filtro, abra um cartão. A solicitação que você está interessado aparecerá no momento da ação.
- Encontre a resposta com seus dados. O método mais rápido é Ctrl+F na aba Network: procure um valor único que você vê na tela (código do produto, preço exato, parte do nome) e veja qual solicitação o gerou.
- Copie a solicitação inteira: clique com o botão direito na linha → Copiar → Copiar como cURL. Em seguida, converta para código através do curlconverter — assim você não perderá nenhum cabeçalho.
Caminhos característicos que vale a pena observar em primeiro lugar: /api/, /v1/, /v2/, /search, /products, /listings, /graphql.
Caso especial: sites em Next.js
Aqui, os dados muitas vezes não requerem uma solicitação separada — eles estão diretamente no HTML. No antigo Pages Router, isso é o bloco __NEXT_DATA__. No App Router (Next.js 13 e mais recente), os dados para hidratação estão distribuídos em chamadas self.__next_f.push() em vários nós de script — esse é o payload serializado dos React Server Components. Analisá-lo manualmente é desagradável: os chunks se referem uns aos outros através de prefixos $ e podem ser cortados no meio de uma string. Para Python, existe uma biblioteca nextflight, que analisa tanto o Flight-payload do HTML quanto a resposta RSC bruta (solicitação com o cabeçalho RSC: 1), e sugere buscar por nomes de chaves, em vez de índices de array — assim o parser sobrevive a uma nova implantação do site.
Reversão de parâmetros: paginação e filtros
O endpoint encontrado quase sempre é parametrizado. Existem três esquemas:
- Pela página:
?page=3&per_page=20 - Deslocamento e limite:
?offset=40&limit=20 - Cursor:
?after=<token>&limit=20— o token da próxima página vem no corpo da resposta anterior
Três regras que economizam horas de depuração:
- Pare em um lote vazio, e não em um número de páginas pré-calculado: o contador
totalem APIs privadas mente mais do que gostaríamos. - Verifique o tamanho real do lote. Se você solicitou 100 e recebeu 20 — significa que o endpoint tem seu próprio teto, e sua aritmética de páginas já está errada.
- Não tente acessar a página 500. A paginação profunda é frequentemente cortada pelo servidor; em vez disso, corte a seleção com filtros — por categoria, por faixa de preço, por data.
Por que cURL do navegador funciona, mas seu código não
Este é o ponto de falha mais comum, e a razão quase sempre é uma: cabeçalho perdido. O cURL copiado carrega todo o contexto da solicitação, enquanto um cliente escrito à mão não.
O que geralmente se revela obrigatório:
- Cabeçalhos personalizados com o prefixo
X-—X-CSRF-Token,X-Requested-With: XMLHttpRequeste váriosX-*-Tokenque o frontend insere automaticamente. Sem eles, você receberá uma resposta na faixa de 400–500. Referer— cabeçalho contextual gerado pela ação do usuário. Muitos endpoints verificam se a solicitação "veio da sua página".Authorization: Bearer <JWT>— um token de curta duração, geralmente de 15 a 60 minutos. Hardcodá-lo não faz sentido: é necessário saber como obter um novo.- Cookies de sessão — mantenha-os em um objeto de sessão, em vez de copiá-los manualmente.
- Tipo de conteúdo correto
Content-Typepara POST:application/jsoneapplication/x-www-form-urlencodedcodificam o corpo de maneira diferente, e a discrepância com o tipo declarado quebra a solicitação silenciosamente.
Onde procurar os próprios tokens, se não estiverem nos cookies: no código-fonte HTML dentro de <script> (buscando por um valor conhecido através de Ctrl+F), em bundles JavaScript, no localStorage ou IndexedDB — aba Application no DevTools.
Armadilhas que são descobertas tarde demais
A API privada muda sem aviso. Ela não tem versionamento, promessas de compatibilidade ou suporte: a equipe de frontend renomeia um campo na quinta-feira à noite, e seu parser coleta vazio. A proteção não é um "seletor confiável", mas sim o controle da estrutura: verifique se os campos obrigatórios estão presentes e do tipo correto; monitore a proporção de valores vazios e o número de registros em execução; ignore registros corrompidos, mas alerte se a taxa de erros exceder 10%; armazene respostas brutas para que haja algo para comparar depois.
A API às vezes é mais protegida do que a página. Isso acontece regularmente: o HTML é entregue sem problemas, enquanto em /api/ há um anti-bot que verifica tanto a impressão digital do TLS quanto a combinação de cabeçalhos. Assim, a economia de tráfego se transforma em um aumento na proporção de solicitações malsucedidas, e o ganho é consumido.
Solicitações assinadas. Se nos parâmetros houver algo como sign, hash ou _s, o frontend calcula a assinatura em JavaScript. Reproduzi-la é um projeto à parte, e muitas vezes é mais barato ficar com o HTML.
Limitações de taxa. Endpoints privados não são projetados para fluxo: mantenha 1–2 solicitações por segundo, defina timeouts separados para conexão e leitura (por exemplo, 5 e 30 segundos), repita apenas erros transitórios — 429, 500, 502, 503, 504 — e não toque em 401 e 404. Um atraso exponencial com jitter é obrigatório, caso contrário, todos os workers irão para a segunda rodada ao mesmo tempo. Para mais detalhes, veja a análise sobre timeouts e lógica de retry para proxies.
Quadro jurídico. Endpoints públicos não autenticados são uma situação, enquanto o acesso à conta é fundamentalmente diferente: o registro implica na aceitação do contrato de usuário. Dados pessoais estão sujeitos ao GDPR, independentemente de quão facilmente possam ser obtidos. Fatos — preços, características, disponibilidade — não são protegidos por direitos autorais, ao contrário de textos e imagens.
Quando permanecer no HTML
A API oculta nem sempre é vantajosa. Continue analisando páginas se:
- o site é servidor e não há nenhuma API interna;
- o endpoint requer assinatura ou rotação de tokens — mantê-lo é mais caro do que a página;
- a API possui uma proteção mais rigorosa do que as páginas públicas;
- você precisa exatamente do resultado final, que o frontend compila de várias fontes;
- você está lidando com dezenas de sites: uma única linha de montagem HTML escala melhor do que um zoológico de APIs privadas com peculiaridades individuais.
Qual tipo de proxy usar para parsing de API
A transição para JSON muda a contagem, pois o gargalo se desloca: o tráfego diminui, mas as exigências de qualidade de IP e estabilidade de sessão aumentam.
- Endpoint aberto sem autorização e sem anti-bot. Aqui, são suficientes proxies de data center: o volume de dados é pequeno, não há necessidade de pagar por residenciais.
- Endpoint atrás de anti-bot ou vinculado à sessão. Necessita de proxies residenciais com sessão persistente: token, cookie e IP devem coincidir durante toda a cadeia, caso contrário, o servidor descartará a sessão na segunda solicitação. Nesse caso, a conta permanecerá modesta — gigabytes em modo JSON são consumidos lentamente.
- Dados de um aplicativo móvel. Se a versão web estiver fechada e o aplicativo fornecer a mesma coisa de forma mais simples, os endpoints são encontrados através da interceptação de tráfego — esse é um procedimento separado, discutido no artigo sobre como encontrar a API oculta de um aplicativo móvel usando mitmproxy.
Resumindo
Vinte minutos no DevTools frequentemente substituem dias de luta com um navegador headless: filtro Fetch/XHR, busca por um valor visível, Copiar como cURL — e você tem uma solicitação funcional em mãos. Depois, os detalhes são resolvidos: transferir todos os cabeçalhos, analisar o esquema de paginação, implementar validação de resposta e avaliar com clareza se o endpoint não está mais protegido do que a própria página. Onde a API privada funciona, ela reduz tanto o volume de tráfego quanto o número de solicitações — ou seja, imediatamente reduz tanto o custo do proxy quanto a probabilidade de banimento.
