Voltar ao blogue
Guias
Mihnea-Octavian ManolacheLast updated on May 12, 202612 min read

Como construir um Web Scraper com Pyppeteer (Guia 2026)

Como construir um Web Scraper com Pyppeteer (Guia 2026)
Resumo: O Pyppeteer é a versão não oficial do Puppeteer para Python e continua a funcionar para controlar um Chromium real a partir de asyncio. Neste guia, irá instalá-lo e escrever um scraper web moderno com o Pyppeteer utilizando asyncio.run e try/finally, lidar com tempos de espera, formulários, capturas de ecrã, rolagem infinita, cookies e proxies, e aprender quando migrar para o Playwright, o Selenium ou uma API de scraping hospedada.

Se já ultrapassaste requests e do BeautifulSoup porque os dados de que precisa só aparecem após a execução do JavaScript, provavelmente já pensou em criar um scraper web com o Pyppeteer. O Pyppeteer é a versão em Python do Puppeteer e permite-lhe iniciar uma instância real do Chromium, aguardar seletores, clicar em botões e executar JavaScript arbitrário dentro da página a partir de async código Python. Isso é suficiente para extrair aplicações de página única, feeds de rolagem infinita, interfaces de pesquisa e qualquer outra coisa que se esconda por trás de uma fetch chamada.

Este guia foi escrito para programadores Python de nível intermédio em 2026. Abordaremos uma análise honesta do estado do projeto, uma comparação com o Selenium, o Playwright e o Node Puppeteer, padrões assíncronos modernos (asyncio.run, try/finally, esperas estruturadas) e um exemplo completo de ponta a ponta que percorre várias palavras-chave numa interface de pesquisa orientada por JavaScript. No final, terá um modelo de scraper Pyppeteer funcional, além de um quadro de decisão claro para saber quando o Pyppeteer é a ferramenta certa e quando não é.

Pyppeteer em 2026: onde se encaixa e o que mudou

O Pyppeteer é, na sua essência, um wrapper Python que espelha a API do Puppeteer: launch um navegador, abrir uma page, chamar waitForSelector, executar evaluate, repetir. O modelo mental corresponde exatamente ao projeto Puppeteer original no GitHub, o que é útil se já leu um tutorial do Node e quis continuar a usar Python.

A advertência honesta para 2026 é que o Pyppeteer recebe apenas uma manutenção mínima. Os mantenedores afirmam no README do projeto que a manutenção é mínima, e várias funcionalidades mais recentes do Puppeteer nunca foram portadas. Isso não significa que o seu scraper irá deixar de funcionar amanhã, mas significa que não deve escolher o Pyppeteer para um sistema de produção de longa duração sem ponderar o Playwright e uma API de scraping gerida como alternativas. Voltaremos a essa decisão no final.

Pyppeteer vs Selenium, Playwright e Puppeteer

Antes de se comprometer, é útil comparar o Pyppeteer com as suas alternativas mais próximas. A tabela abaixo é um guia rápido para que possa escolher a ferramenta certa para a sua pilha, em vez de optar por aquilo que aparecer primeiro no Google.

Ferramenta

Linguagem

Modelo assíncrono

Navegadores

Opções de ocultação

Manutenção

Pyppeteer

Python

Nativo asyncio

Chromium

Manual, sem plugin nativo

Manutenção mínima

Playwright (Python)

Python

Sincronização + asyncio

Chromium, Firefox, WebKit

Predefinições integradas favoráveis ao modo furtivo

Desenvolvido ativamente pela Microsoft

Selenium

Python (e outros)

Sincronização (assíncrona através de wrappers)

Chromium, Firefox, Edge, Safari

selenium-stealth, controladores não detetados

Ativamente mantido, maduro

Puppeteer (Node)

JavaScript / TypeScript

Promessas nativas

Chromium, Firefox (experimental)

puppeteer-extra-plugin-stealth

Desenvolvido ativamente pela equipa do Chrome

Leitura prática: escolha o Puppeteer no Node se quiser as funcionalidades mais recentes, o Playwright para novos projetos em Python que necessitem de scraping estável entre navegadores, o Selenium quando for necessário suportar o Safari ou fluxos legados ao estilo do IE, e o Pyppeteer quando um pequeno script em Python ou uma base de código existente já o suportar asyncio. Para uma comparação mais abrangente, consulte os nossos resumos sobre bibliotecas de navegadores headless em Python e alternativas ao Puppeteer.

Configurar o Pyppeteer (correções para Python, Chromium e M1/M2)

Utilize Python 3.10 ou mais recente e um ambiente virtual. Com o `uv`, a instalação é feita com uma única linha de comando:

uv init pyppeteer-demo && cd pyppeteer-demo
uv add pyppeteer
uv run pyppeteer-install   # downloads bundled Chromium

Se preferir o pip, substitua por python -m venv .venv && pip install pyppeteer && pyppeteer-install. Na primeira execução, o Pyppeteer pode baixar uma compilação do Chromium incluída (cerca de 150 MB no momento da redação deste artigo, portanto, verifique novamente as notas de lançamento mais recentes antes de enviar). Para pular esse download e usar o Chromium do sistema, defina PYPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 e passe executablePath para launch:

# macOS:  /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
# Linux:  /usr/bin/google-chrome
# Windows: C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe
await launch(executablePath='/usr/bin/google-chrome', headless=True)

Atenção para Macs M1/M2: o Pyppeteer pode ser um pouco caprichoso arm64. Se o Chromium se recusar a iniciar ou falhar imediatamente, volte a executar o seu terminal no Rosetta e a instalação normalmente conclui-se sem problemas.

Crie um scraper web minimalista com o Pyppeteer: um modelo moderno

Aqui está um ponto de partida reutilizável para um scraper web com o Pyppeteer que usa asyncio.run, envolve o navegador em try/finallye passa o HTML renderizado para o BeautifulSoup. Vamos extrair quotes.toscrape.com/js/, uma página sandbox que renderiza citações via JavaScript, de modo que clientes HTTP simples vejam uma página vazia <body>.

import asyncio
from bs4 import BeautifulSoup
from pyppeteer import launch

URL = 'https://quotes.toscrape.com/js/'

async def scrape() -> list[dict]:
    browser = await launch(headless=True, args=['--no-sandbox'])
    try:
        page = await browser.newPage()
        await page.goto(URL, {'waitUntil': 'networkidle2'})
        await page.waitForSelector('.quote')
        html = await page.content()
        soup = BeautifulSoup(html, 'html.parser')
        return [
            {
                'text': q.select_one('.text').get_text(strip=True),
                'author': q.select_one('.author').get_text(strip=True),
            }
            for q in soup.select('.quote')
        ]
    finally:
        await browser.close()

if __name__ == '__main__':
    for row in asyncio.run(scrape()):
        print(row)

Três coisas são importantes aqui. asyncio.run substitui o padrão antigo get_event_loop().run_until_complete padrão que os tutoriais mais antigos ainda mostram. try/finally garante que o Chromium seja fechado mesmo quando o seu código gera uma exceção. E waitForSelector é o ponto de sincronização explícito, não um sleep que desperdiça tempo em páginas rápidas e expira nas lentas.

Esperar pelos elementos da maneira certa

O Pyppeteer oferece várias opções de espera, e a escolha é importante. waitFor() é vago e propenso a erros porque espera que «alguma coisa» aconteça, enquanto waitForSelector() é explícito e só é resolvido quando o nó de destino existe no DOM. Opte por waitForNavigation após um envio e use waitUntil='networkidle2' quando a página emitir chamadas em segundo plano fetch em segundo plano. Como alternativa, pode chamar page.waitFor(5000) para fazer uma pausa de cinco segundos, mas trate qualquer espera de tempo fixo como último recurso, pois é a maior fonte de scrapers instáveis.

Clicar, digitar e enviar formulários

Para interações mais ricas, combine page.click, page.type (com um pequeno delay para parecer mais humano) e page.keyboard.press. Após enviar um formulário, aguarde a navegação em paralelo com o clique para que a alteração da URL não seja perdida:

await page.type('input[name="q"]', 'pyppeteer', {'delay': 80})
await asyncio.gather(
    page.waitForNavigation({'waitUntil': 'networkidle2'}),
    page.keyboard.press('Enter'),
)

Esse padrão funciona para formulários de login, barras de pesquisa e qualquer interface de utilizador em que um POST acione um redirecionamento.

Capturas de ecrã e exportações para PDF

page.screenshot() capturam a janela de visualização por padrão. Passe fullPage=True para capturas de cima para baixo e chame setViewport primeiro se quiser uma resolução específica. Os PDFs vêm de page.pdf() e funcionam melhor em páginas com estilos de impressão simples:

await page.setViewport({'width': 1440, 'height': 900})
await page.screenshot({'path': 'page.png', 'fullPage': True})
await page.pdf({
    'path': 'page.pdf',
    'format': 'A4',
    'printBackground': True,
    'margin': {'top': '20mm', 'bottom': '20mm', 'left': '15mm', 'right': '15mm'},
})

Lidando com rolagem infinita e carregamento diferido

Páginas com rolagem infinita só renderizam o próximo lote quando você empurra a janela de visualização para a parte inferior. Use page.evaluate para executar um pequeno loop JS que observa document.body.scrollHeight e pára quando este deixa de crescer:

await page.evaluate('''async () => {
  await new Promise(resolve => {
    let last = 0;
    const timer = setInterval(() => {
      window.scrollBy(0, 800);
      const h = document.body.scrollHeight;
      if (h === last) { clearInterval(timer); resolve(); }
      last = h;
    }, 400);
  });
}''')

Limite o loop com um número máximo de iterações se o feed for realmente infinito.

Gerir cookies, sessões e agentes de utilizador

Para páginas com sessão iniciada, inicie sessão uma vez, descarregue os cookies e reproduza-os na próxima execução para não ativar desafios de nova sessão:

cookies = await page.cookies()          # save somewhere safe
await page.setCookie(*saved_cookies)    # restore later
await page.setUserAgent('Mozilla/5.0 ... Chrome/124 Safari/537.36')
await page.setViewport({'width': 1366, 'height': 768})

Emparelhe setUserAgent com um setViewport para que a impressão digital do dispositivo permaneça internamente consistente. Um agente de utilizador de desktop com uma janela de visualização de 320 píxeis é um indício clássico para a deteção de bots.

Scraper web de ponta a ponta com Pyppeteer: a extrair uma interface de pesquisa baseada em JavaScript

Vamos juntar tudo. O script abaixo percorre várias palavras-chave, digita cada uma delas numa barra de pesquisa que apresenta resultados no lado do cliente, aguarda que os cartões de resultados apareçam, extrai os seus títulos com querySelectorAllEvale limpa o campo de entrada antes da próxima palavra-chave. Troque o URL e os seletores para se adequarem ao seu alvo real.

import asyncio
from pyppeteer import launch

KEYWORDS = ['python', 'pyppeteer', 'asyncio']
SEARCH_URL = 'https://example.com/search'   # JS-rendered UI

async def search_one(page, keyword: str) -> list[str]:
    await page.click('input[name="q"]', {'clickCount': 3})
    await page.keyboard.press('Backspace')
    await page.type('input[name="q"]', keyword, {'delay': 60})
    await page.keyboard.press('Enter')
    await page.waitForSelector('.result-card', {'timeout': 10000})
    return await page.querySelectorAllEval(
        '.result-card h3',
        '(nodes) => nodes.map(n => n.innerText.trim())',
    )

async def main():
    browser = await launch(headless=True, args=['--no-sandbox'])
    try:
        page = await browser.newPage()
        await page.goto(SEARCH_URL, {'waitUntil': 'networkidle2'})
        results = {}
        for kw in KEYWORDS:
            results[kw] = await search_one(page, kw)
            await asyncio.sleep(2)   # be polite
        return results
    finally:
        await browser.close()

if __name__ == '__main__':
    print(asyncio.run(main()))

Este padrão permite duas melhorias. Primeiro, reutiliza um navegador e uma página para todas as palavras-chave, o que mantém a execução económica. Segundo, o explícito waitForSelector torna o scraper resistente a instabilidades de rede, pelo que a tarefa não falha no momento em que um pedido demora 600 ms em vez de 200 ms. A partir daqui, introduzir tentativas de repetição e concorrência com asyncio.gather é o próximo passo natural.

Usar proxies e rotação com o Pyppeteer

O Pyppeteer lida com a automação do navegador de forma excelente, mas não gere proxies por si só, pelo que é necessário configurá-los no momento do arranque. A --proxy-server bandeira do Chromium aceita um único endpoint, e page.authenticate adiciona credenciais antes da primeira solicitação:

import random
from pyppeteer import launch

PROXIES = [
    'http://user:pass@proxy-a.example.com:8000',
    'http://user:pass@proxy-b.example.com:8000',
    'http://user:pass@proxy-c.example.com:8000',
]

async def launch_with_proxy():
    proxy = random.choice(PROXIES)   # naive rotation
    host = proxy.split('@')[-1]
    browser = await launch(args=[f'--proxy-server=http://{host}'])
    page = await browser.newPage()
    await page.authenticate({'username': 'user', 'password': 'pass'})
    return browser, page

Mesmo com um proxy limpo, acabará por atingir limites de taxa, por isso faça a rotação por sessão ou por palavra-chave. Para um padrão mais aprofundado, consulte o nosso guia de rotação de proxies em Python. Se gerir os pools por conta própria lhe parecer uma tarefa desnecessária, um produto de proxy residencial gerido ou uma API ao nível do pedido, como a WebScrapingAPI Scraper API, irá aliviar esse trabalho.

Lista de verificação de camuflagem e higiene de impressões digitais

O Pyppeteer é fornecido sem um plugin de camuflagem nativo, pelo que terá de reforçar a segurança do navegador por conta própria. A lista de verificação mínima viável:

  • Defina um agente de utilizador de ambiente de trabalho realista e atual com page.setUserAgent.
  • Combine-o com uma janela de visualização plausível através de page.setViewport (1366x768 ou 1440x900 são padrões seguros).
  • Aplique o navigator.webdriver flag num evaluateOnNewDocument gancho para que ele retorne undefined em vez de true.
  • Mantenha a higiene dos cookies: limpe os cookies entre sessões ou alterne as sessões quando alternar os IPs.
  • Alterne os IPs através de proxies residenciais ou móveis para qualquer alvo com defesas robustas contra bots.
  • Limite as solicitações e humanize o tempo de espera com delay ativar type e pequenos asyncio.sleep intervalos entre as ações.

Melhores práticas de nível de produção para 2026

Se quiser um web scraper com o Pyppeteer que resista a uma programação real, codifique estas regras:

  • Execute o ponto de entrada com asyncio.run(main()). Esqueça get_event_loop() e loop.run_until_complete(); a função moderna é mais limpa e apresenta menos erros.
  • Envolva todos os navegadores em try/finally para que o processo do Chromium seja encerrado mesmo quando o seu código gerar um erro. Navegadores com memória não liberada são a principal causa de falhas nos executores de CI.
  • Prefira waitForSelector (explícito) em vez de waitFor (vago). Reserve intervalos de espera fixos apenas para atrasos anti-bot documentados.
  • Limite a taxa de pedidos de forma educada. Respeite robots.txt, limite-se a dados públicos e adicione jitter para que 100 pedidos não cheguem em 100 milissegundos.
  • Adicione registo estruturado (uma linha JSON por página) e capture o URL, o estado, o tempo de resposta e as contagens de correspondência do seletor. Vai agradecer a si mesmo na primeira vez que um site de destino alterar o seu HTML.

Quando o Pyppeteer é a ferramenta errada (e o que usar em vez disso)

O Pyppeteer é ideal para scripts pontuais, automação interna e pequenas bases de código Python que já utilizam asyncio. Começa a mostrar a sua idade quando precisas de cobertura entre navegadores, funcionalidades CDP recentes, discrição oficial ou concorrência em grande escala. Usa esta regra de decisão aproximada:

  • Fica com o Pyppeteer para protótipos, scrapers de fim de semana e scripts com menos de algumas centenas de páginas por dia.
  • Mude para o Playwright (Python) quando precisar do Firefox ou do WebKit, de espera automática robusta ou de rastreamento de primeira classe.
  • Mude para o Selenium se precisar de suportar o Safari ou integrar-se numa rede de testes existente.
  • Utilize uma API de scraping hospedada quando estiver a dedicar mais tempo à rotação de proxies, CAPTCHAs e infraestrutura headless do que aos dados propriamente ditos.

Pontos-chave

  • O Pyppeteer é a versão Python do Puppeteer com manutenção reduzida; continuará a funcionar em 2026 para asyncio, mas não é a escolha certa para sistemas de produção de longa duração sem um plano de contingência.
  • Use asyncio.run, try/finallye waitForSelector em vez do antigo evento-loop e waitFor padrões apresentados em tutoriais desatualizados.
  • Um scraper web completo com o Pyppeteer abrange esperas, preenchimento de formulários, capturas de ecrã, PDFs, rolagem infinita, reutilização de cookies e proxies, não apenas goto.
  • Não existe um plugin de camuflagem nativo, pelo que o agente do utilizador, a janela de visualização, navigator.webdriver, a higiene de cookies e a rotação de IPs são da sua responsabilidade.
  • Escolha o Playwright, o Selenium ou uma API de scraping gerida assim que o seu scraper ultrapassar a capacidade de uma única máquina, um único navegador ou um único proxy.

Perguntas frequentes

O Pyppeteer ainda é mantido e seguro de usar em 2026?

Na verdade, não. Os mantenedores afirmam explicitamente no README do projeto no GitHub que o Pyppeteer recebe manutenção mínima, e os recursos mais recentes do Puppeteer raramente são portados para ele. Ele ainda funciona e ainda faz scraping, mas para um sistema de produção de longa duração, deve avaliar o Playwright (Python) ou uma API de scraping hospedada como uma alternativa desenvolvida mais ativamente antes de se comprometer.

Qual é a diferença entre o Pyppeteer e o Puppeteer?

O Puppeteer é a biblioteca oficial do Node.js da equipa do Chrome para automatizar o Chromium. O Pyppeteer é uma versão não oficial em Python que espelha a maior parte da API do Puppeteer, mas utiliza asyncio em vez de Promises. O Pyppeteer fica normalmente atrás do Puppeteer em termos de novas funcionalidades, e algumas APIs do Puppeteer estão completamente ausentes, pelo que os ecossistemas são semelhantes na forma, mas não na área de cobertura.

Devo escolher o Pyppeteer, o Playwright ou o Selenium para um novo projeto de scraping em Python?

Para um novo projeto em 2026, opte por padrão pelo Playwright em Python. É desenvolvido ativamente, suporta o Chromium, o Firefox e o WebKit, e inclui uma funcionalidade de espera automática que elimina grande parte da instabilidade. Escolha o Selenium se precisar do Safari ou de uma rede de testes existente. Escolha o Pyppeteer apenas quando estiver a ampliar um script antigo que já o utilize.

O Pyppeteer consegue contornar o Cloudflare, a deteção de bots ou CAPTCHAs por si só?

Não. O Pyppeteer é fornecido sem um plugin de camuflagem e não possui um solucionador de CAPTCHA integrado. Pode reduzir a sua impressão digital manualmente definindo um agente de utilizador realista, aplicando patches navigator.webdrivere alternando IPs residenciais, mas superar os desafios modernos do Cloudflare ou do hCaptcha de forma fiável implica normalmente uma estrutura reforçada ou uma API de scraping ao nível do pedido que trate do desbloqueio por si.

Por que é que o meu script do Pyppeteer falha em Macs M1 ou M2?

O Chromium incluído é sensível ao Apple Silicon. A solução mais comum é reiniciar o terminal no Rosetta e executar novamente pyppeteer-install, o que permite que a compilação x86_64 do Chromium seja instalada e iniciada corretamente. Como alternativa, defina PYPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 e aponte executablePath para um arm64Google Chrome nativo que já tenha instalado.

Conclusão

Criar um web scraper com o Pyppeteer em 2026 continua a ser uma escolha razoável quando se pretende um script Python pequeno e compatível com assíncrono que controle um Chromium real. Dispõe de um modelo inicial funcional, padrões para esperas, formulários, capturas de ecrã, rolagem infinita, cookies e proxies, além de uma lista de verificação de discrição e uma noção clara de quando avançar para o Playwright, o Selenium ou uma alternativa gerida.

A conclusão honesta: o facto de o Pyppeteer ser pouco mantido significa que deve tratá-lo como uma ferramenta tática, em vez de uma plataforma a longo prazo. Envolva o seu navegador em try/finally, prefira waitForSelector em vez de pausas fixas e reserve um orçamento para um plano de migração para o dia em que um site alvo atualizar as suas defesas contra bots mais rapidamente do que o Pyppeteer implementa a próxima funcionalidade do CDP.

Se a rotação de proxies, CAPTCHAs ou atualizações do Chromium começarem a consumir mais tempo do que a própria extração, transfira a camada de pedidos para a API Scraper da WebScrapingAPI e mantenha o seu código Pyppeteer focado na análise dos dados que realmente lhe interessam.

Sobre o autor
Mihnea-Octavian Manolache, Desenvolvedor Full Stack @ WebScrapingAPI
Mihnea-Octavian ManolacheDesenvolvedor Full Stack

Mihnea-Octavian Manolache é engenheiro Full Stack e DevOps na WebScrapingAPI, onde desenvolve funcionalidades do produto e mantém a infraestrutura que garante o bom funcionamento da plataforma.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.