Raspagem da Web RNet: Imitação de Impressão Digital TLS do Navegador
Senior Web Scraping Engineer
TL;DR:
- rnet é um cliente HTTP assíncrono que imita a impressão digital TLS de um navegador real, assim, um servidor que perfilou o handshake vê o Chrome, e não um padrão Python. É construído em Rust e exposto ao Python.
- O que o rnet não faz é renderizar JavaScript. Uma impressão digital perfeita aceita a solicitação; não executa os scripts que constroem o conteúdo de uma página.
- A impressão digital é real neste guia. Uma execução ao vivo imitando o Chrome produziu um JA3 em forma de navegador e um JA4
t13d1516h2sobre HTTP/2 — e ainda assim não encontrou 0 blocos de citação em uma página construída por script. - rnet também é o cliente que chama o Scrapeless. O mesmo cliente assíncrono POSTou a URL para a API de Extração Universal do Scrapeless, obteve o HTML renderizado e puxou todos os 10 autores.
- Duas problemas diferentes, claramente divididos. rnet lida com a camada de impressão digital TLS; Scrapeless lida com a renderização. Nenhum substitui o outro.
- Grátis para começar do lado de fetch. Crie sua chave da API do Scrapeless em app.scrapeless.com.
O que é o rnet, e o que não é
rnet é um cliente HTTP assíncrono para Python construído sobre a pilha de rede do Rust, e sua característica distintiva é a imitação da impressão digital TLS e HTTP. Quando um cliente abre uma conexão TLS, a forma exata do seu handshake — ordem de cifras, extensões, curvas — forma uma impressão digital que os servidores podem perfilar; um cliente Python padrão tem uma impressão digital que nenhum navegador produz, e alguns sites a rejeitam antes que um único byte de HTML seja servido. rnet reproduz o handshake de um navegador escolhido, de modo que a conexão aparece como Chrome ou Firefox, e faz isso sobre HTTP/2 com uma API assíncrona.
O que não é, é um renderizador. Uma impressão digital correspondente permite que você passe pela perfuração do nível do handshake; não faz nada sobre JavaScript. A página ainda constrói seu conteúdo com scripts, e o rnet, como qualquer cliente HTTP, retorna o markup enviado pelo servidor — que em uma página construída por script está vazio de conteúdo. Assim, um scraper rnet separa dois problemas que muitas vezes são confundidos: a camada de impressão digital, onde o rnet ganha seu lugar, e a camada de renderização, que precisa de um navegador. Este guia usa a API de Extração Universal do Scrapeless para a renderização, com o rnet fazendo a chamada. Para uma visão mais ampla, o tutorial de web scraping em Python é o complemento.
Instalação
rnet é toda a cadeia de ferramentas para este guia. A versão contra a qual foi escrito é rnet 2.4.2:
bash
pip install "rnet==2.4.2"
Mantenha sua chave no ambiente, nunca no código fonte:
bash
export SCRAPELESS_API_KEY="sk_your_scrapeless_key"
Imite um navegador e veja onde ele para
Aponte o rnet para um endpoint de identificação de impressão digital com uma configuração de imitação de navegador, e o handshake será lido como esse navegador. JA3 e JA4 são resumos padrão do handshake TLS — a impressão digital negociada sob o padrão TLS 1.3 — e o rnet produz valores em forma de navegador. No entanto, o mesmo cliente em uma página construída por script não encontra nada, porque a impressão digital não tem relação com a renderização do lado do cliente que preenche a página:
python
# fingerprint.py — um handshake real de navegador e seu limite
import asyncio
import json
import re
import rnet
FINGERPRINT_URL = "https://tls.peet.ws/api/all"
PAGE_URL = "https://quotes.toscrape.com/js/"
async def main() -> None:
client = rnet.Client(impersonate=rnet.Impersonate.Chrome131)
resp = await client.get(FINGERPRINT_URL)
fp = json.loads(await resp.text())
ja3 = fp.get("tls", {}).get("ja3_hash", "")
ja4 = fp.get("tls", {}).get("ja4", "")
print("ja3 é 32-hex:", bool(re.fullmatch(r"[0-9a-f]{32}", ja3)))
print("prefixo ja4:", ja4.split("_")[0])
print("versão http:", fp.get("http_version"))
page_resp = await client.get(PAGE_URL)
page = await page_resp.text()
print("blocos de citação da página js:", page.count('class="quote"'))
asyncio.run(main())
O handshake está em forma de navegador; a página ainda está vazia:
text
ja3 é 32-hex: True
prefixo ja4: t13d1516h2
versão http: h2
blocos de citação da página js: 0
O hash JA3 varia de execução para execução por design — os navegadores randomizam uma extensão sob o mecanismo GREASE, e o rnet reproduz isso — então um scraper verifica a forma, não um valor fixo. O prefixo JA4 t13d1516h2 é a parte estável: TLS 1.3, 16 suítes de cifras, 16 extensões, HTTP/2. O que nada disso faz é renderizar a página.
Renderizar com Scrapeless, chamado pelo rnet
Mantenha o mesmo cliente assíncrono e mude o alvo: faça um POST da URL para a API de Scraping Universal da Scrapeless, que renderiza no lado do servidor e retorna o HTML final. O rnet lida com essa solicitação como qualquer outra, então um cliente cobre tanto as recuperações sensíveis à impressão digital quanto as renderizadas:
python
# rendered.py — rnet chama a API de renderização e, em seguida, extrai
import asyncio
import json
import os
import re
import rnet
async def main() -> None:
client = rnet.Client(impersonate=rnet.Impersonate.Chrome131)
resp = await client.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"x-api-token": os.environ["SCRAPELESS_API_KEY"], "Content-Type": "application/json"},
json={"actor": "unlocker.webunlocker", "input": {"url": "https://quotes.toscrape.com/js/", "js_render": True}},
)
html = json.loads(await resp.text())["data"]
authors = re.findall(r'<small class="author">(.*?)</small>', html)
print("blocos de citações renderizadas:", html.count('class="quote"'))
print("primeiro autor:", authors[0])
asyncio.run(main())
Agora o conteúdo está presente:
text
blocos de citações renderizadas: 10
primeiro autor: Albert Einstein
Esse é todo o scraper, e ele permaneceu no rnet o tempo todo: o cliente assíncrono que carrega uma impressão digital de navegador também faz a chamada de renderização. A API de Scraping Universal faz a renderização; o rnet faz o HTTP.
Obtenha sua chave de API no plano gratuito: app.scrapeless.com
Padrões avançados
- Combine a simulação com um navegador atual.
rnet.Impersonateexpõe versões específicas de navegadores; escolha uma recente, já que uma impressão digital de um build antigo é ela mesma um sinal. A API do cliente não muda com o alvo. - Reutilize um cliente. Um
rnet.Clientagrupa conexões; crie-o uma vez e compartilhe-o entre um grupo de tarefas assíncronas em vez de por solicitação, que é onde o transporte assíncrono se paga. - Verifique a forma, não o valor. Porque o GREASE randomiza o JA3 por conexão, assegure o padrão de 32 hexadecimais e o prefixo JA4, como faz o primeiro script — nunca um hash codificado.
- Adicione um parser quando a forma crescer. A regex mantém isso com uma dependência; para registros aninhados, forneça o HTML renderizado a uma biblioteca de seletores e selecione os campos lá.
Solução de problemas
- Um site ainda bloqueia a solicitação. Uma impressão digital TLS é um sinal entre muitos. Se um handshake com formato de navegador não é suficiente, o bloqueio está acima do transporte — reputação de IP, cabeçalhos ou um desafio — e a solicitação pertence ao caminho Scrapeless, que lida com isso.
- Sem bloqueios de uma página que você pode ver em um navegador. O conteúdo é renderizado em JavaScript; a impressão digital fez com que a solicitação fosse aceita, mas os scripts nunca foram executados. Rote essa URL pela chamada Scrapeless com
js_render. - O hash JA3 muda a cada execução. Isso está correto — o GREASE o randomiza, exatamente como um navegador real faz. Assegure o padrão e o prefixo JA4 em vez disso.
- Erros de
awaitna resposta. rnet é assíncrono: tanto a solicitação quanto a leitura de.text()são aguardadas, e tudo é executado dentro deasyncio.run, como mostram os exemplos.
Conclusão
O rnet ganha seu lugar como a camada que faz o handshake parecer correto: um cliente assíncrono, suportado por Rust, que carrega a impressão digital TLS de um navegador real e que também faz a chamada de renderização. O problema que ele não resolve é a própria página — o resultado de zero bloqueios do script de impressão digital resolve isso — e um POST Scrapeless, enviado pelo rnet, fecha a lacuna. Conecte a camada de impressão digital e a camada de renderização em um único cliente e os dez autores da página de demonstração retornam de uma conexão que um servidor lê como Chrome.
Criando uma conta gratuita na Scrapeless para obter uma chave de API, e a documentação do desenvolvedor cobre os parâmetros unlocker.webunlocker. Verifique os preços da Scrapeless ao planejar um trabalho recorrente.
FAQ
Q: O rnet pode raspar páginas renderizadas em JavaScript por si só?
Não. O rnet é um cliente HTTP com simulação de impressão digital; ele aceita uma solicitação na camada TLS, mas não executa JavaScript. Em uma página construída por script, a recuperação retorna uma marcação com o conteúdo ausente — o resultado de zero bloqueios do guia. Rote essas páginas pela API de Scraping Universal da Scrapeless, que as renderiza, com o rnet fazendo a chamada.
Q: O que a simulação de impressão digital TLS realmente faz?
Ele molda o handshake TLS do rnet para corresponder a um navegador escolhido, de modo que um servidor que perfil trata o fingerprint JA3 ou JA4 veja Chrome ou Firefox em vez de um cliente Python genérico. Isso limpa a filtragem em nível de handshake; não remove bloqueios baseados em IP, páginas de desafio ou a necessidade de renderizar JavaScript.
P: Como o rnet difere do curl_cffi?
Ambos usam fingerprints de navegador. O rnet é construído em Rust e é assíncrono; o curl_cffi envolve o curl-impersonate e é sincrono. Escolha com base em se seu scraper é assíncrono e quais alvos de impersonação você precisa — o padrão de duas camadas com uma API de renderização é o mesmo de qualquer forma.
P: Por que o hash JA3 muda em cada execução?
Porque navegadores reais randomizam uma extensão TLS através do mecanismo GREASE, e o rnet reproduz esse comportamento. Um JA3 fixo pareceria artificial. Verifique o padrão de 32 hexadecimais e o prefixo JA4 em vez de um valor específico.
P: É legal fazer scraping com o rnet?
O cliente HTTP não muda as regras de coleta. Busque apenas páginas públicas, respeite os termos do site e as diretivas de robôs padronizadas pelo Protocolo de Exclusão de Robôs, mantenha os volumes limitados e trate qualquer dado pessoal de acordo com as leis que se aplicam a você.
Na Scorretless, acessamos apenas dados disponíveis ao público, enquanto cumprem estritamente as leis, regulamentos e políticas de privacidade do site aplicáveis. O conteúdo deste blog é apenas para fins de demonstração e não envolve atividades ilegais ou infratoras. Não temos garantias e negamos toda a responsabilidade pelo uso de informações deste blog ou links de terceiros. Antes de se envolver em qualquer atividade de raspagem, consulte seu consultor jurídico e revise os termos de serviço do site de destino ou obtenha as permissões necessárias.



