Você comprou proxies residenciais, configurou um novo User-Agent do Chrome, mas o site ainda retorna 403 na primeira solicitação. Isso soa familiar? O problema não está no IP nem nos cabeçalhos. Você foi identificado antes mesmo de o servidor ler qualquer cabeçalho HTTP — pelo handshake TLS. Em 2026, esse é o vetor de detecção número 1, e o comum requests falha automaticamente. Vamos analisar como isso funciona e como corrigir com algumas linhas de código usando curl_cffi.
O que está acontecendo: você é detectado pelo handshake TLS
Quando o cliente estabelece uma conexão HTTPS, ele primeiro envia um pacote ClientHello — antes de qualquer HTTP. Nele estão listados: a versão do TLS, a lista de conjuntos de cifras suportados (cipher suites), extensões TLS (SNI, ALPN, supported_groups), curvas elípticas e formatos de pontos. A ordem e a composição desses campos variam entre diferentes clientes e são diferentes — e com isso, o cliente pode ser identificado antes mesmo de pronunciar uma palavra.
Esses campos são usados para calcular uma impressão digital. JA3 (padrão de 2017) pega uma string do tipo TLSVersion,Ciphers,Extensions,EllipticCurves,ECPointFormats e a hash com MD5, resultando em uma assinatura de 32 caracteres. O problema do JA3 é que, desde janeiro de 2023, o Chrome randomiza a ordem das extensões — 16 extensões geram 16! (mais de 20 trilhões) de combinações, e o mesmo navegador fornece diferentes JA3.
Por isso, a indústria mudou para JA4 (FoxIO, implementação em massa em 2024–2025). O JA4 ordena os códigos de extensão pelo valor hex antes da hash — a randomização do Chrome não o quebra mais. A hash é um SHA-256 truncado, o formato é legível e dividido em três partes (a_b_c), incluindo ALPN e suporte a QUIC/HTTP3. Exemplo: Chrome 124 gera t13d1516h2 (15 cifras, 16 extensões, ALPN h2), enquanto o Python puro requests gera t13d1715h2. Para um anti-bot, a segunda assinatura é um marcador direto de "isto é um script".
Por que em 2026 isso é imprescindível
A detecção JA4 está embutida em todos os grandes fornecedores: Cloudflare verifica a impressão digital contra listas de permissão, Akamai adiciona uma hash separada para quadros de configurações HTTP/2, DataDome compara com um banco de dados de bots conhecidos. A lógica é simples e letal: se você envia User-Agent: Chrome 131, mas a impressão digital TLS grita "urllib3/OpenSSL" — isso é desincronização, e você é bloqueado instantaneamente. Nenhum proxy salva: um IP residencial perfeito com a impressão digital do Python requests ainda perde.
É exatamente por isso que a combinação "proxy + falsificação de impressão digital" se tornou em 2026 uma higiene básica de scraping, e não uma opção para avançados.
Solução: curl_cffi em 5 minutos
curl_cffi é uma camada Python sobre curl-impersonate (curl modificado, construído com BoringSSL do Chrome ou NSS do Firefox em vez de OpenSSL). Ele reproduz o handshake de navegador autêntico e possui uma API quase idêntica ao familiar requests.
Passo 1. Instalação. Os binários do curl-impersonate para Windows/macOS/Linux são baixados automaticamente:
pip install curl-cffi
Passo 2. Solicitação básica. Altere a importação e adicione um parâmetro:
from curl_cffi import requests
resp = requests.get("https://target.com/", impersonate="chrome")
print(resp.status_code)
print(resp.http_version) # HTTP/2 — como um navegador real
Uma linha impersonate="chrome" falsifica imediatamente quatro camadas: impressão digital TLS (JA3/JA4), versão HTTP (HTTP/2 em vez de HTTP/1.1), ordem dos cabeçalhos e negociações ALPN.
Passo 3. Sempre use o alias genérico, e não a versão fixa. Escreva impersonate="chrome" (ou "safari", "safari_ios") — o alias é resolvido automaticamente para o perfil mais recente. O impersonate="chrome124" ficará obsoleto: o Chrome é atualizado a cada ~4 semanas, e o perfil antigo se tornará uma anomalia. Alvos confiáveis — Chrome, Edge e Safari/iOS (perfis de chrome99 a chrome131, safari15–18).
Passo 4. Proxies e sessões. Para scraping real, mantenha o estado em uma sessão e conecte proxies. Um IP residencial ou móvel é obrigatório aqui — um data center é identificado separadamente do TLS pelo ASN:
from curl_cffi import requests
session = requests.Session(impersonate="chrome")
headers = {
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Referer": "https://www.google.com/",
}
proxies = {
"http": "http://user:pass@proxy-host:port",
"https": "http://user:pass@proxy-host:port",
}
resp = session.get("https://target.com", headers=headers, proxies=proxies)
Passo 5. Assincronismo para volume. Ao contrário do requests, o curl_cffi já possui suporte a async e HTTP/2:
import asyncio
from curl_cffi.requests import AsyncSession
async def fetch(session, url):
r = await session.get(url, impersonate="chrome")
return r.status_code
async def main(urls):
async with AsyncSession() as session:
return await asyncio.gather(*[fetch(session, u) for u in urls])
asyncio.run(main(["https://target.com"] * 20))
Verifique sua impressão digital — não adivinhe
Antes de enviar tráfego de produção, certifique-se de que a falsificação realmente funciona. Envie uma solicitação para verificadores públicos e compare o JA4 com o do navegador padrão:
- tls.peet.ws — retorna JA3, JA4, impressão Akamai e quadros HTTP/2 em JSON. Solicite através do
curl_cffie através do Chrome real, e compare os hashes. - ja4db.com — banco de dados de JA4 conhecidos, ajuda a entender com quem você se parece.
- browserleaks.com/tls e a ferramenta JA3/JA4 do Scrapfly — detalhamento dos campos.
No staging, é conveniente colocar mitmproxy entre o scraper e o alvo e monitorar o hash JA4 real de cada solicitação.
Diagnóstico: ainda recebendo 403/429
Se a impressão digital estiver correta, mas os bloqueios persistirem — siga a lista de verificação do mais comum ao mais raro:
- IP de data center. Razão nº 1. Mude para proxies residenciais ou móveis — por que uma impressão digital sozinha não é suficiente, explicado detalhadamente no material sobre detecção de proxies residenciais através de IP Intelligence.
- Perfil obsoleto.
pip install -U curl-cffie alias genérico"chrome". - Taxa muito alta. Adicione pausas aleatórias de 1 a 3 segundos entre as solicitações.
- Cabeçalhos nus. Sempre envie
Accept-Language,Accept-Encoding,Referer— a ausência deles também é uma anomalia. - Desincronização entre sessão e IP. Regra: uma sessão — um IP durante toda a sua vida útil.
- Status 200 ≠ sucesso. Verifique o corpo da resposta: sob o código 200 pode haver uma página com CAPTCHA.
Onde o curl_cffi encontra limites
curl_cffi fecha a camada de rede — e ponto. Ele não executa JavaScript. Portanto, contra desafios de JS, ele é impotente: Cloudflare Turnstile, página "Checking your browser…" (IUAM), cookie cf_clearance que é definido pelo script após a verificação — tudo isso requer um ambiente de navegador real. Por que em 2026 os solucionadores de CAPTCHA quase pararam de funcionar contra esses sistemas preventivos, discutimos em uma análise separada sobre bypass de CAPTCHA.
O que fazer quando você encontra uma parede de JS:
- Híbrido. Playwright ou Nodriver executa o desafio e obtém
cf_clearance, em seguida, o cookie é passado para o rápidocurl_cffipara a maioria das solicitações — assim você paga por um navegador pesado uma única vez. - Serviços de solucionadores (CapSolver, 2Captcha) para emissão automática de tokens.
- API de scraping gerenciado, se você não quiser manter a infraestrutura.
E lembre-se da segurança de thread: cada thread deve ter sua própria sessão. Fixe a versão curl-cffi em requirements.txt e revise os perfis a cada 6–12 semanas, quando os navegadores forem atualizados.
Alternativas ao curl_cffi
- tls-client — uma camada sobre a biblioteca Go baseada em uTLS, com perfis (
chrome_124,safari_ios_17) e a flagrandom_tls_extension_order=True. Ajuste flexível da impressão digital. - primp — cliente em Rust, permite definir
impersonate_osde forma independente e oferece maior largura de banda; desvantagem — a API não coincide totalmente comrequestse a biblioteca é mais nova.
Qual proxy é necessário e por quê
A falsificação de impressão digital e proxies resolvem diferentes partes de uma mesma tarefa: curl_cffi fecha a questão de "como é a conexão", enquanto o proxy responde "de onde ela vem". O anti-bot verifica ambos os sinais de forma independente, portanto, um JA4 ideal com ASN de data center negro é inútil. Para objetivos protegidos (marketplaces, redes sociais, agregadores de viagens), utilize proxies residenciais ou móveis: eles têm uma origem operadora limpa, e os móveis ainda se escondem atrás do efeito CGNAT "efeito de multidão". Deixe o data center para objetivos menos sensíveis e alto volume.
Conclusão
Em 2026, scraping é um jogo de identidades, e não apenas de IPs. O requests puro se apresenta como um script no nível do handshake TLS e perde antes mesmo do primeiro cabeçalho. Substituir a importação por curl_cffi com impersonate="chrome" elimina essa falha em cinco minutos, mas funciona apenas em conjunto com um IP residencial ou móvel limpo e com a compreensão do limite: camada de rede — sim, desafios de JavaScript — não. Monte sua pilha de forma honesta: impressão digital correta, proxy correto, híbrido com navegador onde houver uma parede de JS — e o 403 na primeira solicitação ficará no passado.
