Cheerio vs. Puppeteer para raspagem da web

Um olhar sobre as diferenças entre o “Puppeteer” e o “Cheerio”, através da construção de um raspador da web com ambos.
12 min read
Cheerio vs. Puppeteer featured image

Cheerio e Puppeteer são duas bibliotecas Node.js que lhe permitem navegar programaticamente na Internet. Devido a isto, ambas são escolhas populares para aqueles que desejam construir um raspador da web node.js a partir do zero.  

A fim de comparar o Cheerio com o Puppeteer, vamos construir um simples raspador da web com o Cheerio e um raspador da web com o Puppeteer. Utilizaremos ambas as ferramentas para raspar todos os links do blogue de In Plain English, uma plataforma de programação popular.

Mas antes de começarmos, vamos ver o que vamos discutir neste artigo:

Diferenças entre Cheerio e Puppeteer

Há muitas diferenças entre essas 2 bibliotecas, e cada uma delas vem com as suas próprias características especiais que pode aproveitar para a raspagem da web.

Cheerio

  • Cheerio é um analisador DOM, capaz de analisar ficheiros HTML e XML.
  • É uma implementação rápida e simples do núcleo jQuery concebida especificamente para o servidor.
  • Se planeia usar isto para raspar um sítio web, terá de usar o Cheerio em conjunto com uma biblioteca de cliente http do Node.js como o https://axios-http.com/docs/introAxios.  
  • O Cheerio não mostra o sítio web como um navegador (não aplica CSS nem carrega recursos externos).
  • Devido a isto, terá dificuldade em tentar raspar SPAs construídas com tecnologias de vanguarda como a React.
  • O Cheerio não pode interagir com um sítio (por exemplo, não pode clicar em botões) nem aceder ao conteúdo de scripts.
  • Tem uma curva de aprendizagem fácil graças à sua sintaxe simples. Os usuários de jQuery se sentirão em casa aqui.
  • O Cheerio é rápido em comparação com o Puppeteer.

Puppeteer

  • O Puppeteer é uma ferramenta de automatização do navegador. Tem acesso a todo o motor do navegador (geralmente o Chromium).
  • Isto torna-o uma opção mais versátil, em comparação com o Cheerio.
  • Pode executar JavaScript, tornando-o capaz de raspar páginas dinâmicas como aplicações de página única (SPAs).
  • O Puppeteer pode interagir com sítios web, o que significa que pode ser usado para clicar em botões, digitar em formulários de registo, etc.
  • Tem uma curva de aprendizagem íngreme, uma vez que tem mais funcionalidades e requer frequentemente o uso de código assíncrono (ou seja, promessas/async await).
  • O Puppeteer é lento em comparação com o Cheerio.

Construir um Raspador da Web com o Cheerio

Primeiro, vamos criar uma pasta chamada ‘raspador’ para o nosso código. Dentro de ‘raspador’, correr npm init -y ou yarn init -y, dependendo de ter optado por usar npm ou yarn.  

Agora que temos a nossa pasta pronta e package.json inicializado, vamos instalar os nossos pacotes.  

Nota: Pode consultar o nosso guia principal de raspagem da web com node.js que inclui o uso de Cheerio e Axios para raspagem da web com mais detalhe.  

Passo 1 – Instalação de Cheerio

Para instalar o Cheerio, execute o seguinte comando no seu terminal:

// using npm
npm install cheerio

// or using yarn
yarn add cheerio

Passo 2 – Instalação de Axios

Axios é uma biblioteca popular para fazer pedidos HTTP no Node.js. Pode ser utilizado para fazer chamadas de API, obter dados de sítios web, e muito mais.

Para o instalar, execute o seguinte comando no seu terminal:

// using npm
npm install axios

// or using yarn
yarn add axios

Utilizamos Axios para fazer pedidos HTTP para o sítio web que pretendemos raspar. A resposta que obtemos do sítio web é sob a forma de HTML, que podemos então analisar e extrair a informação de que precisamos utilizando o Cheerio.

Passo 3 – Preparar o nosso raspador

Vamos entrar na nossa pasta ‘raspador’ e criar um ficheiro chamado cheerio.js.  

Aqui está a estrutura básica do código para começar com a raspagem da web usando Cheerio e Axios:

const axios = require('axios');
const cheerio = require('cheerio');

axios
 .get("https://plainenglish.io/blog")
 .then((response) => {
   // Initialize links array which we will push the links to later
   let links = [];

   // HTML Markup
   const body = response.data;

   // Load HTML data and initialize cheerio
   const $ = cheerio.load(body);

   // CSS selector for the target element
   const element = ".PostPreview_container__82q9E";

   // Loop through each matching element and extract the text content
   $(element).each(function () {
     // Loop through each matching element and get the href attribute of each element
     const _link = $(this).find("a").prop("href");

     // We check if the link is undefined because cheerio will return undefined if the element doesn't exist
     if (_link !== undefined) {
       // Add the link to the links array
       links.push(`https://plainenglish.io` + _link);
     }
   });

   return links;
 })
 .then((response) => {
   console.log(response);
 });

No código acima, precisamos primeiro as bibliotecas Axios e Cheerio.

Passo 5 – Processamento dos dados

A seguir, fazemos um pedido get() para “https://plainenglish.io/blog”. Porque o Axios é assíncrono, nós encadeamos a nossa função get() com then().  

Inicializamos uma matriz de links vazia para capturar os links que planeamos raspar.

Passamos então o response.data de Axios para Cheerio com:  

// HTML Markup
const body = response.data;

// Load HTML data and initialize cheerio
const $ = cheerio.load(body);
We choose which selector we plan to target, in our case:
// CSS selector for the target element
const element = ".PostPreview_container__82q9E";

Passo 5 – Processamento dos dados

Depois, fazemos um laço através de cada elemento correspondente, encontramos a etiqueta <a>, e agarramos o valor da propriedade href. Para cada partida, empurramo-la para a nossa matriz de links:  

// Loop through each matching element and extract the text content
$(element).each(function () {
 // Loop through each matching element and get the href attribute of each element
 const _link = $(this).find("a").prop("href");

 // We check if the link is undefined because cheerio will return undefined if the element doesn't exist
 if (_link !== undefined) {
   // Add the link to the links array
   links.push(`https://plainenglish.io` + _link);
 }
});

Depois os devolvemos, encadeamos outro then() e enviamos ao console.log a nossa resposta.    

Passo 6 – Resultados finais

Finalmente, se abrirmos um terminal de dentro da nossa pasta ‘raspador’, podemos correr o node.js cheerio.js. Isto irá executar todo o código do nosso ficheiro cheerio.js. Deverá ver os URLs da nossa matriz de links a serem enviados para a consola. Ficará algo parecido com isto:  

 'https://plainenglish.io/blog/how-to-implement-a-search-bar-in-react-js',
 'https://plainenglish.io/blog/how-to-build-data-driven-surveys-with-react-rest-api-surveyjs',
 'https://plainenglish.io/blog/handle-errors-in-angular-with-httpclient-and-rxjs',
 'https://plainenglish.io/blog/deploying-a-localhost-server-with-node-js-and-express-js',
 'https://plainenglish.io/blog/complete-guide-to-data-center-migration',
 'https://plainenglish.io/blog/build-a-stripe-app-with-typescript-and-node-js-part-2',
 ... 861 more items

E assim mesmo, conseguimos raspar o sítio In Plain English!

A partir daqui, podemos ir um passo mais longe e guardar os dados num ficheiro, em vez de simplesmente enviá-los para a consola.

O Cheerio e o Axios facilitam a execução de raspagem da web no Node.js. Com apenas algumas linhas de código, é possível extrair dados de sítios web e utilizá-los para vários fins.  

Construir um Raspador da Web com Puppeteer

Vamos para a nossa pasta ‘raspador’ e criemos um ficheiro chamado puppeteer.js. Já inicializámos o nosso package.json, mas se saltou para esta secção, vá em frente e inicialize agora esse ficheiro.  

Uma vez inicializado, vamos instalar o Puppeteer.

Passo 1 – Instalação do Puppeteer

Para instalar o Puppeteer, executar um dos seguintes comandos:

// using npm
npm install puppeteer

// or using yarn
yarn add puppeteer

Passo 2 – Preparar o nosso raspador

Vamos para a nossa pasta ‘raspador’ e criemos um ficheiro chamado puppeteer.js.  

Aqui está a estrutura básica do código para começar com a raspagem da web usando o Puppeteer:

const puppeteer = require("puppeteer");

// Because everything in Puppeteer is asynchronous,
// we wrap all of our code inside of an async IIFE
(async () => {
 // Initialize links array which we will push the links to later
 let links = [];

 // Launch Puppeteer
 const browser = await puppeteer.launch();

 // Create a new page
 const page = await browser.newPage();

 // Go to URL
 await page.goto("https://plainenglish.io/blog");

 // Set screen size
 await page.setViewport({ width: 1080, height: 1024 });

 // CSS selector for the target element
 const element = ".PostPreview_container__82q9E";

 // Get all matching elements
 const elements = await page.$$(element);

 // Wrapped with Promise.all to wait for all promises to resolve before continuing
 const _links = await Promise.all(
   // Get the href attribute of each element
   elements.map(async (el) => el.evaluate((el) => el.children[0].href))
 );

 if (_links.length) {
   // If there are any links
   _links.forEach((url) => {
     // Loop through each link
     links.push(url); // Add the link to the links array
   });
 }

 console.log(links);

 await browser.close();
})();

No código acima, precisamos primeiro a biblioteca Puppeteer.

Passo 3 – Criação de uma IIFE

A seguir, criamos uma expressão de função imediatamente invocada (IIFE). Como tudo no Puppeteer é assíncrono, colocamos async no início. Em outras palavras, temos isto:  

(async () => {
// ...code goes here
}()

Dentro da nossa IIFE assimétrica, criamos uma matriz de links vazia, que utilizaremos para capturar os links do blogue que estamos a raspar.

// Initialize links array which we will push the links to later
let links = []

A seguir, executamos o Puppeteer, abrimos uma nova página, navegamos para um URL, e definimos o suporte de visualização da página (o tamanho da tela).

 // Launch Puppeteer
 const browser = await puppeteer.launch();

 // Create a new page
 const page = await browser.newPage();

 // Go to URL
 await page.goto("https://plainenglish.io/blog");

 // Set screen size
 await page.setViewport({ width: 1080, height: 1024 });

Por defeito, o Puppeteer corre em ‘modo sem cabeça’. Isto significa que não abre um navegador que se possa ver visualmente. No entanto, definimos um tamanho de visualização pois queremos que o Puppeteer navegue pelo sítio a uma certa largura e altura.

Nota: Se decidir que gostaria de ver o que o “Puppeteer” está a fazer em tempo real, pode passar a opção “headless: false” como parâmetro, assim:  

// Launch Puppeteer
const browser = await puppeteer.launch({ headless: false });

Passo 5 – Processamento dos dados

A partir daqui, escolhemos qual é o seletor que pretendemos visar, no nosso caso:

// CSS selector for the target element
const element = ".PostPreview_container__82q9E";

E executamos o que equivale à querySelectorAll() para o nosso elemento alvo:  

// Get all matching elements
const elements = await page.$$(element);

Nota: $$ não é o mesmo que querySelectorAll, por isso não espere ter acesso a todas as mesmas coisas.

Passo 5 – Processamento dos dados

Agora que temos os nossos elementos armazenados dentro de elementos, mapeamos cada elemento para retirar a propriedade href:  

// Wrapped with Promise.all to wait for all promises to resolve before continuing
const _links = await Promise.all(
 // Get the href attribute of each element
 elements.map(async (el) => el.evaluate((el) => el.children[0].href))
);

No nosso caso de uso específico, temos el.children[0], pois sei que o primeiro elemento secundário do nosso elemento alvo é uma etiqueta a, e é a etiqueta a cujo valor eu quero.  

Em seguida, fazemos um laço através de cada elemento mapeado e empurramos o valor para a nossa matriz de links, desta forma:

if (_links.length) {
 // If there are any links
 _links.forEach((url) => {
   // Loop through each link
   links.push(url); // Add the link to the links array
 });
}

Finalmente, enviamos os links ao console.log, e depois fechamos o navegador:  

console.log(links);

await browser.close();

Nota: Se não fechar o navegador, este permanecerá aberto e o seu terminal ficará suspenso.  

Passo 6 – Resultados finais

Agora, se abrirmos um terminal de dentro da nossa pasta ‘raspador’, podemos executar node.js puppeteer.js. Isto executará todo o código do nosso ficheiro puppeteer.js. Deverá ver os URLs da nossa matriz de links a serem enviados para a consola. Ficará algo parecido com isto:  

'https://plainenglish.io/blog/how-to-implement-a-search-bar-in-react-js',
 'https://plainenglish.io/blog/how-to-build-data-driven-surveys-with-react-rest-api-surveyjs',
 'https://plainenglish.io/blog/handle-errors-in-angular-with-httpclient-and-rxjs',
 'https://plainenglish.io/blog/deploying-a-localhost-server-with-node-js-and-express-js',
 'https://plainenglish.io/blog/complete-guide-to-data-center-migration',
 'https://plainenglish.io/blog/build-a-stripe-app-with-typescript-and-node-js-part-2',
 ... 861 more items

E assim mesmo, conseguimos raspar o sítio web com o Puppeteer!

Puppeteer é uma ferramenta poderosa para raspar e automatizar tarefas de navegação na web. Fornece uma API rica para tarefas de raspagem e automatização de navegação na web. Pode utilizá-la para extrair informação de sítios web, gerar capturas de ecrã e PDFs, e realizar muitas outras tarefas.

Se quiser usar o Puppeteer para raspar os principais sítios, deve considerar integrar o Puppeteer com um proxy, para evitar ficar bloqueado.  

Nota: Existem outras alternativas ao “Puppeteer”, tais como o Selenium, ou o IDE para Raspador da Web. Ou, se quiser poupar tempo, pode saltar todo o processo de raspagem da web completamente, procurando conjuntos de dados prontos.  

Conclusão

Se procura raspar páginas estáticas sem a necessidade de interações tais como cliques e envios de formulários (ou qualquer tipo de tratamento de eventos), o Cheerio é a escolha ideal.

No entanto, se o sítio web depende do JavaScript para a injeção de conteúdo, ou se precisa de tratar eventos, é necessário o Puppeteer.

Qualquer que seja a abordagem que decidir, vale a pena notar que este caso de uso específico foi bastante simples. Se tentar raspar algo mais complexo, como um sítio web dinâmico (YouTube, Twitter, ou Facebook, por exemplo), poderá encontrar-se em águas bastante profundas.  

Se procura raspar sítios web e não quer perder semanas a tentar decifrar uma solução, talvez seja melhor procurar uma solução pronta a usar, tal como o IDE para Raspador da Web.  

O IDE da Bright Data inclui funções de raspagem pré-fabricadas, infraestrutura proxy de desbloqueio sofisticada incorporada, scripts de navegador em JavaScript, depuração, e vários modelos de raspagem prontos a usar para sítios web populares.

More from Bright Data

Datasets Icon

Get immediately structured data

Access reliable public web data for any use case. The datasets can be downloaded or delivered in a variety of formats. Subscribe to get fresh records of your preferred dataset based on a pre-defined schedule.

Web scraper IDE Icon

Build reliable web scrapers. Fast.

Build scrapers in a cloud environment with code templates and functions that speed up the development. This solution is based on Bright Data's Web Unlocker and proxy infrastructure making it easy to scale and never get blocked.

Web Unlocker Icon

Implement an automated unlocking solution

Boost the unblocking process with fingerprint management, CAPTCHA-solving, and IP rotation. Any scraper, written in any language, can integrate it via a regular proxy interface.

Ready to get started?