Uma visão geral do Web Scraping com o Puppeteer
A Google concebeu o Puppeteer para fornecer uma interface simples, mas poderosa, no Node.js para automatizar testes e várias tarefas utilizando o motor do navegador Chromium. Por predefinição, funciona sem interface gráfica, mas pode ser configurado para executar o Chrome ou o Chromium na íntegra.
A API criada pela equipa do Puppeteer utiliza o Protocolo DevTools para assumir o controlo de um navegador web, como o Chrome, e realizar diferentes tarefas, tais como:
- Capturar imagens e gerar PDFs de páginas
- Automatizar o envio de formulários
- Testar a interface do utilizador (clicar em botões, introduzir dados via teclado, etc.)
- Extrair dados de uma SPA e gerar conteúdo pré-renderizado (Renderização do Lado do Servidor)
A maioria das ações que pode realizar manualmente no navegador também pode ser feita utilizando o Puppeteer. Além disso, podem ser automatizadas para que possa poupar mais tempo e concentrar-se noutros assuntos.
O Puppeteer também foi concebido para ser intuitivo para os programadores. Quem estiver familiarizado com outras estruturas de teste populares, como o Mocha, sentir-se-á em casa com o Puppeteer e encontrará uma comunidade ativa que oferece apoio ao Puppeteer. Isto levou a um enorme crescimento da popularidade entre os programadores.
É claro que o Puppeteer não é adequado apenas para testes. Afinal, se ele consegue fazer tudo o que um navegador padrão consegue, então pode ser extremamente útil para web scrapers. Nomeadamente, pode ajudar na execução de código JavaScript para que o scraper consiga aceder ao HTML da página e imitar o comportamento normal de um utilizador, percorrendo a página ou clicando em secções aleatórias.
Estas funcionalidades tão necessárias tornam os navegadores headless um componente essencial para qualquer ferramenta comercial de extração de dados e para todos os web scrapers caseiros, exceto os mais simples.
Pré-requisitos
Em primeiro lugar, certifique-se de que tem as versões atualizadas do Node.js e do Puppeteer instaladas no seu computador. Se não for esse o caso, pode seguir os passos abaixo para instalar todos os pré-requisitos.
Pode descarregar e instalar o Node.js a partir daqui. O gestor de pacotes padrão do Node, o npm, vem pré-instalado com o Node.js.
Para instalar a biblioteca Puppeteer, pode executar o seguinte comando no diretório raiz do seu projeto:
npm install puppeteer
# or "yarn add puppeteer"
Note que, ao instalar o Puppeteer, também é descarregada a versão mais recente do Chromium, que é garantidamente compatível com a API.
O Puppeteer em ação
Há muitas coisas diferentes que pode fazer com a biblioteca. Uma vez que o nosso foco principal é a extração de dados da Web, falaremos sobre os casos de utilização que provavelmente mais lhe interessarão se pretender extrair dados da Web.
Fazer uma captura de ecrã
Vamos começar com um exemplo básico. Vamos escrever um script que irá capturar uma captura de ecrã de um site à nossa escolha.
Tenha em mente que o Puppeteer é uma biblioteca baseada em promessas (ele realiza chamadas assíncronas para a instância do Chrome sem interface gráfica nos bastidores). Por isso, vamos manter o código limpo usando async/await.
Primeiro, crie um novo ficheiro chamado index.js no diretório raiz do seu projeto.
Dentro desse ficheiro, precisamos de definir uma função assíncrona e envolvê-la em todo o código do Puppeteer.
const puppeteer = require('puppeteer')
async function snapScreenshot() {
try {
const URL = 'https://old.reddit.com/'
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.goto(URL)
await page.screenshot({ path: 'screenshot.png' })
await browser.close()
} catch (error) {
console.error(error)
}
}
snapScreenshot()
Primeiro, uma instância do navegador é iniciada usando o comando puppeteer.launch(). Em seguida, criamos uma nova página usando a instância do navegador. Para navegar até ao site desejado, podemos usar o método goto(), passando o URL como parâmetro. Para capturar uma imagem, usaremos o método screenshot(). Também precisamos de passar o local onde a imagem será guardada.
Note que o Puppeteer define um tamanho inicial de página de 800×600px, o que define o tamanho da captura de ecrã. Pode personalizar o tamanho da página utilizando o método setViewport().
Não se esqueça de fechar a instância do navegador. Depois, basta executar node index.js no terminal.
É mesmo assim tão simples! Deverá agora ver um novo ficheiro chamado screenshot.png na pasta do seu projeto.
Enviar um formulário
Se, por algum motivo, o site que pretende rastrear não mostrar o conteúdo a menos que esteja conectado, pode automatizar o processo de login com o Puppeteer.
Primeiro, precisamos de inspecionar o site que estamos a extrair e encontrar os campos de login. Podemos fazer isso clicando com o botão direito do rato no elemento e escolhendo a opção Inspecionar.
No meu caso, os campos de entrada estão dentro de um formulário com a classe login-form. Podemos introduzir as credenciais de login utilizando o método type().
Além disso, se quiseres garantir que ele executa as ações corretas, podes adicionar o parâmetro headless e defini-lo como false ao lançares a instância do Puppeteer. Verás então como o Puppeteer realiza todo o processo por ti.
const puppeteer = require('puppeteer')
async function login() {
try {
const URL = 'https://old.reddit.com/'
const browser = await puppeteer.launch({headless: false})
const page = await browser.newPage()
await page.goto(URL)
await page.type('.login-form input[name="user"]', 'EMAIL@gmail.com')
await page.type('.login-form input[name="passwd"]', 'PASSWORD')
await Promise.all([
page.click('.login-form .submit button'),
page.waitForNavigation(),
]);
await browser.close()
} catch (error) {
console.error(error)
}
}
login()
Para simular um clique do rato, podemos usar o método click(). Depois de clicarmos no botão de login, devemos esperar que a página carregue. Podemos fazer isso com o método waitForNavigation().
Se introduzimos as credenciais corretas, já devemos estar a fazer login!
Extrair várias páginas
Vou usar o subreddit /r/learnprogramming para este artigo. Portanto, queremos navegar até ao site e recolher o título e o URL de cada publicação. Vamos usar o método evaluate() para isso.
O código deve ficar assim:
const puppeteer = require('puppeteer')
async function tutorial() {
try {
const URL = 'https://old.reddit.com/r/learnprogramming/'
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.goto(URL)
let data = await page.evaluate(() => {
let results = []
let items = document.querySelectorAll('.thing')
items.forEach((item) => {
results.push({
url: item.getAttribute('data-url'),
title: item.querySelector('.title').innerText,
})
})
return results
})
console.log(data)
await browser.close()
} catch (error) {
console.error(error)
}
}
tutorial()
Usando o método Inspect apresentado anteriormente, podemos obter todas as publicações selecionando o seletor .thing. Iteramos por elas e, para cada uma, obtemos a URL e o título e colocamo-los numa matriz.
Depois de todo o processo estar concluído, pode ver o resultado na sua consola.
Ótimo, já extraímos a primeira página. Mas como é que extraímos várias páginas deste subreddit?
É mais simples do que pensas. Aqui está o código:
const puppeteer = require('puppeteer')
async function tutorial() {
try {
const URL = 'https://old.reddit.com/r/learnprogramming/'
const browser = await puppeteer.launch({headless: false})
const page = await browser.newPage()
await page.goto(URL)
let pagesToScrape = 5;
let currentPage = 1;
let data = []
while (currentPage <= pagesToScrape) {
let newResults = await page.evaluate(() => {
let results = []
let items = document.querySelectorAll('.thing')
items.forEach((item) => {
results.push({
url: item.getAttribute('data-url'),
text: item.querySelector('.title').innerText,
})
})
return results
})
data = data.concat(newResults)
if (currentPage < pagesToScrape) {
await page.click('.next-button a')
await page.waitForSelector('.thing')
await page.waitForSelector('.next-button a')
}
currentPage++;
}
console.log(data)
await browser.close()
} catch (error) {
console.error(error)
}
}
tutorial()
Precisamos de uma variável para saber quantas páginas queremos extrair e outra variável para a página atual. Enquanto a página atual for menor ou igual ao número de páginas que queremos extrair, obtemos a URL e o título de cada publicação na página. Depois de cada página ser extraída, concatenamos os novos resultados com os já extraídos.
Depois, clicamos no botão da página seguinte e repetimos o processo de extração até atingirmos o número desejado de páginas extraídas. Também precisamos de incrementar a página atual após cada página.
Uma opção ainda mais fácil
Parabéns! Criou com sucesso o seu próprio scraper web com o Puppeteer. Espero que tenha gostado do tutorial!
Mesmo assim, o script que criámos neste guia não consegue realizar tarefas complexas. Faltam-lhe alguns aspetos essenciais que tornam o web scraping perfeito. A utilização de proxies móveis ou residenciais e a resolução de CAPTCHAs são apenas algumas das funcionalidades em falta.
Se procura uma forma mais profissional de extrair dados, veja o que a WebScrapingAPI consegue fazer e veja se é uma boa opção. Existe um pacote gratuito, pelo que tudo o que precisa de investir são 30 minutos do seu tempo.
Boa sorte com o web scraping!




