Como fazer scraping de sites renderizados com JavaScript
Muitos sites modernos enviam um documento HTML quase vazio e constroem o conteúdo no navegador com JavaScript. Se o seu scraper busca a página e não encontra produtos, preços nem texto de artigo, o conteúdo existe, mas chega depois. Este guia mostra como identificar qual tipo de página você tem, como encontrar um caminho mais rápido do que um navegador quando ele existe e como fazer scraping de páginas renderizadas com Playwright em Python. Termina com uma nota sobre o que fazer quando uma página renderizada mostra um captcha.
Passo 1: verifique se o conteúdo está no HTML
Abra a página com view-source: no seu navegador, ou busque-a com uma requisição HTTP simples, e procure no código-fonte um trecho de texto que você consegue ver na tela. Três resultados são comuns:
- O texto está lá. A página é renderizada no servidor. Um cliente HTTP e um parser de HTML bastam, e você deve usá-los, porque são mais rápidos e simples.
- O texto não está, mas há um bloco JSON. Muitos sites incorporam o estado deles em uma tag de script, como
__NEXT_DATA__. Faça o parse desse JSON diretamente. - O texto não está e não há bloco nenhum. A página carrega o conteúdo com requisições adicionais. Olhe a aba Network do DevTools, filtrada em Fetch/XHR, enquanto a página carrega.
Passo 2: chame o endpoint JSON, se existir um
Quando uma página busca os dados de um endpoint, chamar esse endpoint diretamente costuma ser a melhor opção. Ele é menor, mais rápido e mais estável do que a página renderizada. Copie a URL da requisição, verifique quais cabeçalhos o site exige e teste a partir de um script. Faça isso apenas quando os termos do site permitirem, e respeite quaisquer limites de taxa ou autenticação que o site espera. Um endpoint não documentado pode mudar sem aviso, então escreva o seu parser para falhar de forma explícita quando a estrutura da resposta mudar.
Passo 3: renderize a página quando for necessário
Se o conteúdo realmente exige o navegador, use um navegador headless. O Playwright é uma boa escolha para Python. O exemplo abaixo abre uma listagem de produtos, espera o conteúdo aparecer e lê o texto de cada cartão:
from playwright.sync_api import sync_playwright
URL = "https://example.com/products" # uma página que você tem permissão para raspar
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
# Espere pelo elemento que prova que os dados chegaram.
page.wait_for_selector(".product-card", timeout=30_000)
titles = page.locator(".product-card h2").all_inner_texts()
browser.close()
for title in titles:
print(title)
Esperar por um seletor específico é muito mais confiável do que um sleep fixo. Uma pausa fixa é curta demais em um dia lento ou desperdiça tempo em um dia rápido. Escolha o elemento que só aparece depois que os dados carregaram.
Passo 4: trate rolagem infinita e paginação
Algumas páginas carregam mais itens conforme você rola. Role até o fim, espere a contagem de itens crescer e pare quando ela não crescer mais. Páginas com paginação numerada são mais simples: encontre o link da próxima página, siga-o e pare na última. Defina sempre um número máximo de páginas ou rolagens, para que um bug não mantenha o seu crawler rodando para sempre.
def scroll_until_done(page, selector: str, max_rounds: int = 20) -> int:
previous = -1
for _ in range(max_rounds):
count = page.locator(selector).count()
if count == previous:
break
previous = count
page.mouse.wheel(0, 4000)
page.wait_for_timeout(1500) # dê tempo para o próximo lote carregar
return previous
Passo 5: mantenha o navegador econômico
Renderizar é caro. Bloqueie imagens, fontes e mídias de que você não precisa, e reutilize um único navegador para muitas páginas, em vez de iniciar um novo a cada vez. Feche páginas e contextos quando terminar, para que a memória não cresça ao longo de uma execução longa.
def block_heavy_assets(route):
if route.request.resource_type in ("image", "font", "media"):
route.abort()
else:
route.continue_()
page.route("**/*", block_heavy_assets)
Passo 6: quando uma página renderizada mostra um captcha
Às vezes a página renderizada apresenta um captcha antes de mostrar qualquer conteúdo. Se esse captcha for PopularCaptcha, o tipo de captcha ativo na Scarnox, você lê o sitekey da página, solicita um token e coloca o token no campo de formulário que o site espera. O guia de PopularCaptcha em Python percorre essa etapa. Outros widgets ainda não estão ativos, então confira tipos de captcha explicados antes de planejar em cima de um deles.
Tenha cuidado com o próprio navegador. Um navegador headless que parece claramente automatizado pode disparar mais verificações, e não menos. Leia detecção de navegador headless para os sinais a observar, e prefira menos carregamentos de página, mais lentos.
Faça scraping com responsabilidade
- Verifique o
robots.txte os termos do site antes de renderizar a página ou chamar os endpoints dele. - Mantenha os limites de taxa baixos e guarde os resultados em cache, para buscar cada página uma vez.
- Não faça scraping de dados pessoais sem uma base legal.
- Se um site restringe o acesso, pare. Não tente contornar a restrição.
Próximos passos
- Como não ser bloqueado no scraping
- Detecção de navegador headless
- Scraping de sites protegidos pela Cloudflare
- Tratamento de captcha com Playwright e Puppeteer
Comece com crédito de teste grátis, sem cartão: crie uma conta e teste o fluxo de PopularCaptcha em uma página sua. Para as tarifas atuais, veja a página de preços.