Cheerio y Puppeteer son dos librerías Node.js que te permiten navegar programáticamente por internet. Debido a esto, ambas son opciones populares para aquellos que desean construir un raspador web node.js desde cero.
Para comparar Cheerio y Puppeteer, construiremos un raspador web simple con Cheerio y un raspador web con Puppeteer. Usaremos ambas herramientas para raspar datos de todos los enlaces de blogs de In Plain English, una popular plataforma de programación.
Pero antes de empezar, veamos de qué vamos a hablar en este artículo.
- Diferencias entre Cheerio y Puppeteer
- Construir un Web Scraper con Cheerio
- Construir un Web Scraper con Puppeteer
- Conclusión
Diferencias entre Cheerio y Puppeteer
Hay muchas diferencias entre estas 2 bibliotecas, y cada una viene con sus propias características especiales que puede aprovechar para el raspado de datos web.
Cheerio
- Cheerio es un analizador DOM, capaz de analizar archivos HTML y XML.
- Es una implementación rápida y sencilla del núcleo de jQuery diseñada específicamente para el servidor.
- Si planea usar esto para raspar datos en un sitio web, necesitará usar Cheerio en conjunto con una librería cliente http Node.js como Axios.
- Cheerio no renderiza el sitio web como un navegador (no aplica CSS ni carga recursos externos).
- Debido a esto, le será difícil tratar de raspar datos en SPAs construidas con tecnologías frontales como React.
- Cheerio no puede interactuar con un sitio (por ejemplo, no puede hacer clic en botones) ni acceder a contenidos detrás de scripts.
- Tiene una curva de aprendizaje fácil gracias a su sintaxis simple. Los usuarios de jQuery se sentirán como en casa.
- Cheerio es rápido en comparación con Puppeteer.
Puppeteer
- Puppeteer es una herramienta de automatización del navegador. Tiene acceso a todo el motor del navegador (normalmente Chromium).
- Esto la hace una opción más versátil, comparada con Cheerio.
- Puede ejecutar JavaScript, por lo que es capaz de raspar páginas dinámicas como aplicaciones de una sola página (SPA).
- Puppeteer puede interactuar con sitios web, lo que significa que se puede utilizar para hacer clic en botones, escribir en formularios de inicio de sesión, etc.
- Tiene una curva de aprendizaje muy inclinada, ya que tiene más funcionalidades y a menudo requiere el uso de código asíncrono (es decir, promises/async await).
- Puppeteer es lento en comparación con Cheerio.
Construir un raspador web con Cheerio
Primero, creemos una carpeta llamada scraper para nuestro código. Dentro de scraper, ejecute npm init -y
o yarn init -y
, según haya optado por usar npm
o yarn
.
Ahora que tenemos nuestra carpeta lista y package.json
inicializado, vamos a instalar nuestros paquetes.
Nota: Puedes consultar nuestra guía principal de raspado de datos web en node.js que incluye el uso de Cheerio y Axios para raspado de datos web en más detalle.
Paso 1 – Instalación de Cheerio
Para instalar Cheerio, ejecute el siguiente comando en su terminal:
// using npm
npm install cheerio
// or using yarn
yarn add cheerio
Paso 2 – Instalación de Axios
Axios es una popular biblioteca para hacer solicitudes HTTP en Node.js. Puede usarse para hacer llamadas API, obtener datos de sitios web, y más.
Para instalarla, ejecute el siguiente comando en su terminal:
// using npm
npm install axios
// or using yarn
yarn add axios
Usamos Axios para hacer peticiones HTTP al sitio web en el que queremos raspar datos. La respuesta que obtenemos del sitio web es en forma de HTML, que luego podemos analizar y extraer la información que necesitamos usando Cheerio.
Paso 3 – Preparando nuestro Scraper
Vayamos a la carpeta de nuestro scraper y creemos un archivo llamado cheerio.js
.
Esta es la estructura básica del código para comenzar con el raspado web usando Cheerio y 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);
});
En el código anterior, primero necesitamos las bibliotecas Axios y Cheerio.
Paso 4 – Solicitar los datos
A continuación, realizamos una petición get()
a “https://plainenglish.io/blog”. Dado que Axios es asíncrono, encadenamos nuestra función get()
con then()
.
Inicializamos una matriz de enlaces vacía para capturar los enlaces que planeamos raspar.
Luego pasamos el response.data
de Axios a Cheerio con:
// 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";
Paso 5 – Procesamiento de los datos
A continuación, recorremos cada elemento coincidente, buscamos la etiqueta <a>
y obtenemos el valor de la propiedad href
. Para cada coincidencia, lo empujamos a nuestra matriz de enlaces:
// 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);
}
});
Después, devolvemos los enlaces, encadenamos otro then()
y console.log
nuestra respuesta.
Paso 6 – Resultados finales
Por último, si abrimos una terminal dentro de nuestra carpeta scraper, podemos ejecutar node.js cheerio.js
. Esto ejecutará todo el código de nuestro archivo cheerio.js
. Debería ver las URL de nuestra matriz de enlaces en la consola. Se verá algo como esto:
'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
Y así de fácil, ¡hemos conseguido raspar datos en el sitio web In Plain English!
A partir de aquí, podemos ir un paso más allá y guardar los datos en un archivo, en lugar de simplemente enviarlos a la consola.
Cheerio y Axios facilitan el raspado web en Node.js. Con sólo unas pocas líneas de código, puede extraer datos de sitios web y utilizarlos para diversos fines.
Construyendo un Web Scraper con Puppeteer
Vayamos a nuestra carpeta scraper y creemos un archivo llamado puppeteer.js
. Ya hemos inicializado nuestro package.json
, pero si se ha saltado esta sección, siga adelante e inicialice ese archivo ahora.
Una vez inicializado, vamos a instalar Puppeteer.
Paso 1 – Instalando Puppeteer
Para instalar Puppeteer, ejecute cualquiera de los siguientes comandos:
// using npm
npm install puppeteer
// or using yarn
yarn add puppeteer
Paso 2 – Preparando nuestro Scraper
Vayamos a nuestra carpeta scraper y creemos un archivo llamado puppeteer.js
.
Aquí está la estructura básica del código para empezar con el raspado de datos web usando 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();
})();
En el código anterior, primero requerimos la librería Puppeteer.
Paso 3 – Creación de una IIFE
A continuación, creamos una expresión de función inmediatamente invocada (IIFE). Como todo en Puppeteer es asíncrono, ponemos async al principio. En otras palabras, tenemos esto:
(async () => {
// ...code goes here
}()
Dentro de nuestra IIFE asíncrona, creamos un array de enlaces vacío, que usaremos para capturar los enlaces del blog que estamos raspando.
// Initialize links array which we will push the links to later
let links = []
A continuación, lanzamos Puppeteer, abrimos una nueva página, navegamos a una URL, y establecemos el viewport de la página (el tamaño de la pantalla).
// 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 defecto, Puppeteer se ejecuta en “modo headless” (sin interfaz gráfica). Esto significa que no abre un navegador que se pueda ver visualmente. Sin embargo, debemos establecer un tamaño de ventana ya que queremos que Puppeteer navegue el sitio a una cierta anchura y altura.
Nota: si decide que desea ver lo que Puppeteer está haciendo en tiempo real, puede pasar la opción headless: false como un parámetro, así:
// Launch Puppeteer
const browser = await puppeteer.launch({ headless: false });
Paso 4 – Solicitar los datos
A partir de aquí, elegimos el selector al que queremos dirigirnos, en nuestro caso:
// CSS selector for the target element
const element = ".PostPreview_container__82q9E";
Y ejecutamos lo que equivale a querySelectorAll()
para nuestro elemento objetivo:
// Get all matching elements
const elements = await page.$$(element);
Nota: $$
no es lo mismo que querySelectorAll, así que no espere tener acceso a todas las mismas cosas.
Paso 5 – Procesamiento de los datos
Ahora que tenemos nuestros elementos almacenados dentro de elementos, mapeamos cada elemento para extraer la propiedad 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))
);
En nuestro caso de uso específico, tenemos el.children[0]
, ya que sé que el primer elemento hijo de nuestro elemento de destino es una etiqueta a, y es la etiqueta a de la que requiero el valor.
A continuación, hacemos un bucle a través de cada elemento mapeado y empujamos el valor en nuestra matriz de enlaces, así:
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
});
}
Por último, console.log
los enlaces, y luego cerrar el navegador:
console.log(links);
await browser.close();
Nota: si no cierra el navegador, permanecerá abierto y su terminal se colgará.
Paso 6 – Resultados finales
Ahora, si abrimos un terminal desde dentro de nuestra carpeta scraper, podemos ejecutar node.js puppeteer.js
. Esto ejecutará todo el código de nuestro archivo puppeteer.js
. Usted debe ver las direcciones URL de nuestra matriz de enlaces de salida a la consola. Se verá algo como esto:
'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
Y así de fácil, ¡hemos conseguido raspar datos en la web con Puppeteer!
Puppeteer es una potente herramienta para raspado de datos web y automatización de tareas del navegador. Proporciona una rica API para el raspado de datos web y la automatización de tareas del navegador. Puede utilizarlo para extraer información de sitios web, generar capturas de pantalla y archivos PDF, y realizar muchas otras tareas.
Si quiere usar Puppeteer para raspar datos en sitios web importantes, debería considerar integrar Puppeteer con un proxy, para evitar ser bloqueado.
Nota: existen otras alternativas a Puppeteer, como Selenium, o el IDE Web Scraper. O si quiere ahorrar tiempo, puede saltarse todo el proceso de raspado de datos web buscando conjuntos de datos ya creados.
Conclusión
Si lo que busca es raspar páginas estáticas sin necesidad de interacciones como clics y envíos de formularios (o cualquier tipo de manejo de eventos), Cheerio es la mejor opción.
Sin embargo, si el sitio web depende de JavaScript para la inyección de contenido, o si necesita manejar eventos, Puppeteer es necesario.
Cualquiera que sea el enfoque que decida, vale la pena señalar que este caso de uso específico era bastante simple. Si intenta hacer scraping de algo más complejo, como un sitio web dinámico (YouTube, Twitter o Facebook, por ejemplo), es posible que se encuentre en aguas bastante profundas.
Si desea raspar sitios web y no quiere perder semanas intentando crear una solución, quizá le convenga más optar por una solución estándar como el IDE de Web Scraper de Bright Data.
El IDE de Bright Data incluye funciones de raspado prediseñadas, una sofisticada infraestructura proxy de desbloqueo incorporada, secuencias de comandos de navegador en JavaScript, depuración y varias plantillas de raspado listas para usar para sitios web populares.