Puppeteer é uma biblioteca de testes e automação de navegadores que também é boa para raspagem da web. Em comparação com ferramentas mais simples como Axios e cheerio, o Puppeteer permite que os programadores raspem conteúdo dinâmico (ou seja, conteúdo que muda com base nas ações do usuário).
Isto significa que pode utilizá-lo para raspar aplicações web (aplicativos de página única) que carregam o seu conteúdo utilizando JavaScript, que é exatamente o que vai fazer aqui.
Raspagem da web usando o Puppeteer
Neste tutorial, aprenderá a extrair dados estáticos e dinâmicos (ou seja, títulos de publicações e links do blogue da Bright Data) com Puppeteer.
Configuração
Antes de começar o tutorial, é preciso ter certeza de que o Node.js está instalado no seu computador. Pode descarregá-lo a partir da sua página oficial de Descarregas.
Em seguida, crie um diretório para o projeto e navegue até ele com os seguintes comandos:
mkdir puppeteer_tutorial
cd puppeteer_tutorial
npm init -y
Em seguida, instale o Puppeteer com este comando:
npm i puppeteer --save
Este comando também descarrega um navegador dedicado que a biblioteca irá utilizar.
Raspagem de um sítio estático
Como todas as ferramentas de raspagem da web, o Puppeteer permite-lhe raspar o código HTML das páginas web.
Seguem-se os passos que pode seguir para utilizar o Puppeteer para raspar a primeira página de publicações do blogue da Bright Data:
Crie um ficheiro index.js
e importe o Puppeteer:
const puppeteer = require('puppeteer');
Em seguida, insira o modelo necessário para executar o Puppeteer:
(async () => {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null
});
const page = await browser.newPage();
await page.goto('https://brightdata.com/blog');
// all the web scraping will happen here
await browser.close();
})();
Esta função abre um navegador, navega até à página para a raspar e fecha o navegador.
Tudo o que resta fazer é raspar os dados da página.
No Puppeteer, a maneira mais fácil de acessar dados HTML é através do método page.evaluate
. Embora o Puppeteer tenha métodos $
e $$
, que são wrappers úteis para buscar elementos, é mais simples obter todos os dados de page.evaluate
.
No blogue da Bright Data, todos os dados da publicação do blogue são envolvidos numa etiqueta <a>
com a classe brd_post_entry
. O título da publicação está num elemento <h3>
com a classe brd_post_title
. O link para a publicação é o valor href
de brd_post_entry
.
Eis o aspeto de uma função page.evaluate
que extrai esses valores:
const data = await page.evaluate( () => {
let data = [];
const titles = document.querySelectorAll('.brd_post_entry');
for (const title of titles) {
const titleText = title.querySelector('.brd_post_title').textContent;
const titleLink = title.href;
const article = { title: titleText, link: titleLink };
data.push(article);
}
return data;
})
Por fim, pode imprimir os dados na consola:
console.log(data);
O script completo tem o seguinte aspeto:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null
});
const page = await browser.newPage();
await page.goto('https://brightdata.com/blog');
const data = await page.evaluate(() => {
let data = [];
const titles = document.querySelectorAll('.brd_post_entry');
for (const title of titles) {
const titleText = title.querySelector('.brd_post_title').textContent;
const titleLink = title.href;
const article = { title: titleText, link: titleLink };
data.push(article);
}
return data;
})
console.log(data);
await browser.close();
})();
Execute-o chamando node index.js
no terminal. O script deve devolver uma lista de títulos de publicações e hiperligações:
[
{
title: 'APIs for Dummies: Learning About APIs',
link: 'https://brightdata.com/blog/web-data/apis-for-dummies'
},
{
title: 'Guide to Using cURL with Python',
link: 'https://brightdata.com/blog/how-tos/curl-with-python'
},
{
title: 'Guide to Scraping Walmart',
link: 'https://brightdata.com/blog/how-tos/guide-to-scraping-walmart'
},
…
Raspagem de conteúdo dinâmico
A raspagem de conteúdos estáticos é uma tarefa simples que pode ser efetuada facilmente com ferramentas simples. Felizmente, o Puppeteer pode ser utilizado para realizar uma vasta gama de ações, tais como clicar, escrever e rolar. Pode utilizar tudo isto para interagir com páginas dinâmicas e simular ações do usuário.
Uma tarefa comum de raspagem da web com uma biblioteca como esta seria procurar um determinado conjunto de dados na página. Por exemplo, pode querer utilizar o Puppeteer para procurar todas as publicações de Bright Data sobre o Puppeteer.
Eis como o pode fazer:
Quando uma pessoa visita o blogue da Bright Data, aparece por vezes um banner de cookies:
Para resolver este problema, é necessário clicar no botão Aceitar tudo com o seguinte código:
await page.waitForSelector('#brd_cookies_bar_accept', {timeout: 5000})
.then(element => element.click())
.catch(error => console.log(error));
A primeira linha do código espera que apareça um elemento com #brd_cookies_bar
_accept durante 5 segundos. A segunda linha clica nesse elemento. A terceira linha garante que o script não falhe se a barra de cookies não aparecer.
Note que a espera no Puppeteer acontece fornecendo alguma condição pela qual se quer esperar, não definindo um certo tempo de espera para que a ação anterior seja executada. A primeira chama-se espera implícita e a segunda chama-se espera explícita.
A espera explícita no Puppeteer é fortemente desencorajada, pois leva a problemas de execução. Se fornecer um tempo de espera explícito, é provável que seja demasiado longo (o que é ineficiente) ou demasiado curto (o que significa que o script não será executado corretamente).
Passo 2: Procurar publicações
Depois disso, o script precisa de clicar no ícone de pesquisa. Escreva “Puppeteer” e prima novamente o ícone de pesquisa para ativar uma pesquisa:
Isto pode ser feito com o seguinte código:
await page.click('.search_icon');
await page.waitForSelector('.search_container.active');
const search_form = await page.waitForSelector('#blog_search');
await search_form.type('puppeteer');
await page.click('.search_icon');
await new Promise(r => setTimeout(r, 2000));
Este exemplo funciona de forma semelhante ao exemplo do banner de cookies. Depois de clicar no botão, é necessário esperar até que o contentor de pesquisa apareça, razão pela qual o código espera por um elemento que corresponda ao seletor CSS de .search_container.active
.
Além disso, no final, é necessário adicionar uma paragem de dois segundos para que os elementos sejam carregados. Embora as esperas explícitas sejam desaconselhadas no Puppeteer, não existem outras boas opções neste momento.
Na maioria dos sítios web, se ocorrer uma alteração no URL, pode utilizar o método waitForNavigation
. Se aparecer um novo elemento, pode utilizar o método waitForSelector
. Descobrir se alguns elementos são atualizados é um pouco mais difícil e está fora do âmbito deste artigo.
Se quiser experimentar por si próprio, esta resposta do Stack Overflow pode ser útil.
Depois de procurar as publicações, pode utilizar o código que já utilizou para a raspagem de páginas estáticas para obter os títulos das publicações do blogue:
const data = await page.evaluate( () => {
let data = [];
const titles = document.querySelectorAll('.brd_post_entry');
for (const title of titles) {
const titleText = title.querySelector('.brd_post_title').textContent;
const titleLink = title.href;
const article = { title: titleText, link: titleLink };
data.push(article);
}
return data;
})
console.log(data);
Eis o código completo do script:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null
});
const page = await browser.newPage();
await page.goto('https://brightdata.com/blog');
const cookie_bar_accept = await page.waitForSelector('#brd_cookies_bar_accept');
await cookie_bar_accept.click();
await new Promise(r => setTimeout(r, 500));
await page.click('.search_icon');
await page.waitForSelector('.search_container.active');
const search_form = await page.waitForSelector('#blog_search');
await search_form.type('puppeteer');
await page.click('.search_icon');
await new Promise(r => setTimeout(r, 2000));
const data = await page.evaluate( () => {
let data = [];
const titles = document.querySelectorAll('.brd_post_entry');
for (const title of titles) {
const titleText = title.querySelector('.brd_post_title').textContent;
const titleLink = title.href;
const article = { title: titleText, link: titleLink };
data.push(article);
}
return data;
})
console.log(data);
await browser.close();
})();
Pode ser melhor?
Embora seja possível utilizar scripts de raspagem da web com o Puppeteer, não é o ideal. O Puppeteer é feito para automação de testes, o que o torna um pouco incómodo para realizar a raspagem da web.
Por exemplo, se pretende obter escala e eficiência nos seus scripts, é importante poder fazer raspagem sem ser bloqueado. Para o fazer, pode utilizar proxies–portas de ligação entre você e o sítio web que está a raspar. Embora o Puppeteer suporte o uso de proxies, você precisa encontrar e contratar uma rede proxy por conta própria (saiba mais sobre a integração de proxy de Puppeteer com a Bright Data).
Além disso, otimizar o Puppeteer para uso paralelo não é fácil. Se pretender raspar muitos dados, terá de trabalhar arduamente para obter um desempenho ótimo.
Estas desvantagens significam que o Puppeteer é uma boa escolha para pequenos scripts para utilização por hobby, mas levará muito tempo escalar as suas operações se o utilizar.
Caso pretenda algo mais fácil de utilizar, pode escolher uma plataforma de dados web como a Bright Data. Permite às empresas recolher grandes quantidades de dados estruturados da web utilizando ferramentas fáceis de utilizar, como o Navegador de Raspagem (compatível com Puppeteer/Playwright), especialmente concebido para a raspagem.
Conclusão
Neste artigo, você aprendeu a usar o Puppeteer para raspar páginas da web estáticas e dinâmicas.
O Puppeteer pode executar a maioria das ações que um navegador pode fazer, incluindo clicar em itens, escrever texto e executar JavaScript. E devido ao uso de esperas implícitas, os scripts escritos no Puppeteer são rápidos e fáceis de escrever.
Mas também pode haver alguns problemas: o Puppeteer não é a ferramenta mais eficiente para a raspagem da web e a sua documentação não é adequada para principiantes. Também é difícil escalar operações de raspagem usando o Puppeteer se você não estiver bem familiarizado com ele.
Cansado de raspar dados você mesmo? Obtenha conjuntos de dados pré-colhidos ou personalizados.