Você adquiriu um caro IP residencial, configurou a rotação, inseriu um User-Agent realista — mas o parser ainda vai para o captcha ou recebe uma resposta vazia. O problema quase sempre não está no IP, mas na impressão TLS: a biblioteca que você está usando para enviar a solicitação HTTPS "soa" diferente de um navegador real. Sistemas anti-bot como Wildberries, Ozon, Cloudflare e Akamai percebem isso antes mesmo de verificarem seu endereço IP.
O que é impressão TLS e por que é mais importante que o IP
Quando um cliente estabelece uma conexão HTTPS, ele envia ao servidor um pacote ClientHello — parte do handshake TLS. Nele estão criptografados a lista de versões TLS suportadas, o conjunto de cifras (cipher suites), a ordem das extensões (extensions), curvas elípticas e algoritmos de compressão. Este conjunto de parâmetros é único para cada combinação "biblioteca + sistema operacional + versão do stack TLS".
Chrome, Firefox e Safari formam o ClientHello de maneira única, e esse conjunto praticamente não muda de solicitação para solicitação — ao contrário do IP ou User-Agent, que são fáceis de falsificar. Já as bibliotecas HTTP padrão — requests, urllib3, o HttpClient padrão em Java, o stack TLS embutido do Node.js — formam um ClientHello completamente diferente, porque utilizam OpenSSL ou outra biblioteca de forma diferente de um navegador.
É por isso que você pode conectar um IP residencial "limpo", inserir um User-Agent recente do Chrome real — e ainda assim ser bloqueado. O servidor vê um IP de um usuário de uma residência, vê o cabeçalho "Chrome 124", mas o handshake TLS diz: "isso é um script Python". A discrepância é um sinal claro para o anti-bot.
Como os sistemas anti-bot detectam o parser pelo JA3/JA4
Para transformar os parâmetros do ClientHello em um identificador compacto, é utilizado o algoritmo JA3 (e sua versão mais nova JA4). Ele pega a versão do TLS, a lista de cifras, extensões e curvas, concatena-os em uma string e faz um hash através do MD5. O resultado é um hash curto do tipo 769,47-53-5-10...,0-23-65281...,29-23-24,0, que identifica de forma única a "impressão" do cliente.
Provedores de anti-bot (Cloudflare, Akamai, PerimeterX, DataDome — e seus análogos que usam Wildberries e Ozon) mantêm bancos de dados de hashes JA3/JA4 conhecidos de bibliotecas HTTP populares: requests, aiohttp, Scrapy, Node fetch, Java HttpClient, Go net/http. Se o hash coincide com uma assinatura conhecida de "script", e não com a assinatura do Chrome/Firefox/Safari — a solicitação é marcada como suspeita antes mesmo da análise de comportamento.
Em seguida, o sistema verifica a correspondência da impressão TLS com o User-Agent declarado. Se nos cabeçalhos está escrito "Chrome 124 no Windows", mas a impressão TLS corresponde ao OpenSSL 1.1.1 da biblioteca padrão do Python — isso é chamado de incompatibilidade TLS/HTTP, um dos sinais mais confiáveis de detecção de automação. É assim que os parsers são detectados mesmo com um IP residencial ideal e cabeçalhos corretos.
Como verificar sua impressão TLS: ferramentas
Antes de corrigir o problema, é preciso ver o que o servidor vê. Existem vários serviços públicos que mostram seu hash JA3/JA4 e o conjunto completo de parâmetros do ClientHello:
- tls.peet.ws — mostra JA3, JA4, lista de cifras e extensões em formato JSON, conveniente para verificação automática via script.
- ja3er.com — banco de dados de hashes JA3 conhecidos vinculados a bibliotecas e navegadores específicos.
- browserleaks.com/tls — comparação visual da sua impressão com impressões típicas de navegadores.
- Wireshark localmente — se você quiser ver o pacote bruto ClientHello ao enviar uma solicitação do seu script.
O teste prático é simples: abra tls.peet.ws no Chrome comum e anote o hash JA4. Em seguida, envie uma solicitação GET para o mesmo endereço do seu parser (via requests, curl_cffi ou qualquer outra biblioteca) através do mesmo proxy e compare os hashes. Se eles diferirem — o servidor percebe a diferença entre "navegador" e "script" a cada solicitação, independentemente de quão limpo seja o IP.
Verificação em Python: requests, httpx, curl_cffi
Vamos analisar na prática por que as bibliotecas padrão do Python entregam o parser. Uma solicitação comum via requests:
import requests
resp = requests.get("https://tls.peet.ws/api/all", proxies={
"https": "http://user:pass@proxy_host:port"
})
print(resp.json()["tls"]["ja4"])
# O resultado será diferente do JA4 do Chrome real,
# pois requests usa o módulo ssl padrão do Python
O problema é que requests e httpx usam o OpenSSL do sistema através do módulo ssl, e a ordem e o conjunto de extensões TLS estão rigidamente fixados e não coincidem com Chrome/Firefox. A solução é a biblioteca curl_cffi, que usa o curl patchado com perfis TLS reais de navegadores:
from curl_cffi import requests as cffi_requests
resp = cffi_requests.get(
"https://tls.peet.ws/api/all",
impersonate="chrome124",
proxies={"https": "http://user:pass@proxy_host:port"}
)
print(resp.json()["tls"]["ja4"])
# O hash será idêntico ao do Chrome 124 real no desktop
O parâmetro impersonate faz com que o curl_cffi reproduza não apenas o ClientHello, mas também a ordem dos cabeçalhos HTTP/2 (frame order), que também faz parte da impressão. Abordagem semelhante é utilizada pelas bibliotecas tls-client para Go e undetected-chromedriver para aqueles que fazem parsing através de um navegador real, e não através de um cliente HTTP.
Se o parsing é feito através de um navegador headless (Playwright, Puppeteer, Selenium), a impressão TLS é gerada pelo motor Chromium/Firefox e, por padrão, coincide com o navegador real. Mas aqui surge outro problema — assinaturas de automação em nível de JS (flags do webdriver, canvas fingerprint), portanto, para cenários headless, patches adicionais como playwright-stealth são necessários.
TLS + HTTP/2 + cabeçalhos: por que a combinação é importante
A impressão TLS é apenas uma camada de detecção. Sistemas anti-bot comparam vários níveis simultaneamente:
- TLS ClientHello (JA3/JA4) — conjunto de cifras e extensões.
- Impressão HTTP/2 — ordem dos pseudo-cabeçalhos (:method, :path, :authority), configurações do frame SETTINGS, tamanho da janela.
- Cabeçalhos HTTP — ordem e conjunto de cabeçalhos comuns (Accept-Language, Sec-Ch-Ua, Sec-Fetch-*).
- User-Agent — deve corresponder à versão do perfil TLS: se o UA diz "Chrome 124", mas o TLS corresponde ao Chrome 110, isso também é suspeito.
Um erro comum é atualizar o User-Agent para a versão mais recente do Chrome, esquecendo de atualizar o perfil TLS no curl_cffi ou em outra biblioteca. Essa discrepância de versões é percebida pelo anti-bot tão claramente quanto a total ausência de camuflagem. Verifique se a versão impersonate e a versão no User-Agent coincidem, e atualize ambos os parâmetros em sincronia quando novas versões do navegador forem lançadas.
Outro ponto é a ordem dos cabeçalhos. O navegador envia os cabeçalhos em uma ordem estritamente definida, enquanto muitas bibliotecas HTTP os ordenam alfabeticamente ou pela ordem em que foram adicionados ao código. Mesmo que o conjunto de cabeçalhos seja idêntico ao do navegador, uma ordem incorreta é um sinal adicional para sistemas anti-bot avançados como o DataDome.
O papel dos proxies: por que um IP limpo não salva
O IP residencial resolve uma tarefa específica — reduz a suspeita em relação à geografia, ASN e reputação do endereço. IPs de data centers frequentemente estão em listas negras, pois deles flui massivamente tráfego automatizado, enquanto os residenciais pertencem a provedores reais e usuários comuns. Para fazer parsing de Wildberries, Ozon ou Avito, isso é crítico: sem um IP limpo, a solicitação é bloqueada apenas por esse critério, mesmo sem verificar o TLS.
Mas IP e impressão TLS são duas camadas de proteção independentes, e resolvem problemas diferentes. O IP diz ao servidor "de onde" a solicitação veio, a impressão TLS diz "com o que" foi enviada. Portanto, a combinação de um IP limpo e um perfil TLS correto é o mínimo necessário para um parsing estável. Para tarefas com alta frequência de solicitações e um anti-bot agressivo, é melhor usar proxies residenciais, pois eles oferecem uma baixa porcentagem de bloqueios por reputação de IP, mas devem ser combinados com uma biblioteca que reproduza corretamente o perfil TLS de um navegador real.
Para monitoramento de preços em marketplaces, onde a velocidade e o volume de solicitações são importantes, frequentemente são utilizados proxies de data centers em combinação com camuflagem TLS via curl_cffi — isso é mais barato que residenciais e bastante eficaz, se o sistema anti-bot do site não for muito agressivo. E para tarefas onde o site verifica ativamente redes móveis (por exemplo, parsing de versões móveis de aplicativos via API), usam-se proxies móveis — eles oferecem um nível adicional de confiança devido à reputação das redes operadoras.
Checklist de configuração do parser sem detecção
Reúna a verificação em um único processo antes de lançar o parser em produção:
- Meça o hash JA4 do seu script através do tls.peet.ws e compare com um navegador real da mesma versão.
- Use uma biblioteca com suporte a impersonação TLS: curl_cffi (Python), tls-client (Go), CycleTLS (Node.js).
- Sincronize a versão do perfil TLS (impersonate) com a versão no User-Agent.
- Verifique a ordem dos cabeçalhos HTTP — ela deve coincidir com a do navegador real, e não ser alfabética.
- Conecte um IP residencial ou móvel limpo de acordo com a geolocalização da sua tarefa.
- Configure a rotação de IP separadamente do perfil TLS — não os vincule rigidamente.
- Atualize regularmente o perfil TLS ao lançar novas versões do Chrome — assinaturas antigas entram nas bases de dados de anti-bots mais rápido do que parece.
- Para cenários com verificações em JS (Cloudflare Challenge), use um navegador headless com patches stealth em vez de um cliente HTTP limpo.
Comparação de bibliotecas e ferramentas
| Ferramenta | Impressão TLS do navegador | Velocidade | Quando usar |
|---|---|---|---|
| requests / httpx | Não, entrega script | Alta | Sites sem detecção de TLS, APIs internas |
| curl_cffi | Sim, cópia exata | Alta | Marketplaces, anti-bot Cloudflare/Akamai |
| tls-client (Go) | Sim | Muito alta | Alta carga, parsing em massa |
| Playwright / Puppeteer | Sim, motor real | Baixa | JS-render, Cloudflare Challenge, SPAs complexas |
| Scrapy (padrão) | Não | Alta | Sites sem proteção anti-bot rigorosa |
Conclusão
A impressão TLS é uma camada de proteção que muitos parsers ignoram completamente, gastando recursos para encontrar o IP e User-Agent ideais, mas esquecendo que a própria estrutura do handshake TLS revela a automação antes que o servidor olhe para os cabeçalhos. A solução é usar bibliotecas com suporte a impersonação TLS (curl_cffi, tls-client), sincronizar a versão do perfil com o User-Agent e verificar o hash JA4 final antes de lançar em escala.
O IP ainda é um fator importante — sem um endereço limpo, mesmo a impressão TLS ideal não ajudará a contornar o bloqueio por reputação de rede. Para parsing de marketplaces e monitoramento de preços, é sensato combinar a configuração TLS correta com proxies residenciais — essa combinação cobre ambas as camadas de detecção e reduz significativamente a porcentagem de bloqueios em longas sessões de parsing.