Volver al blog
Guías
Gabriel CiociLast updated on Mar 31, 20266 min read

Extracción de datos web con Puppeteer y Node.JS avanzado

Extracción de datos web con Puppeteer y Node.JS avanzado

En lugar de utilizar herramientas comerciales, muchos desarrolladores prefieren crear sus propios rastreadores web. Aunque los productos disponibles cuentan con funciones más completas, no podemos negar los resultados que estos bots pueden ofrecer ni lo divertido que resulta crear uno propio.

En el siguiente artículo, descubrirás los pasos que debes seguir para crear tu propio rastreador web utilizando Node.js y Puppeteer. Programaremos una aplicación que cargue un sitio web, haga una captura de pantalla, inicie sesión en el sitio web utilizando un navegador sin interfaz gráfica y extraiga algunos datos de varias páginas. Tu aplicación irá aumentando en complejidad a medida que avances.

Una visión general del scraping web con Puppeteer

Una visión general del scraping web con Puppeteer

Google diseñó Puppeteer para proporcionar una interfaz sencilla pero potente en Node.js que permite automatizar pruebas y diversas tareas utilizando el motor del navegador Chromium. Por defecto, se ejecuta sin interfaz gráfica, pero se puede configurar para ejecutar Chrome o Chromium completos.

La API creada por el equipo de Puppeteer utiliza el protocolo DevTools para tomar el control de un navegador web, como Chrome, y realizar diferentes tareas, tales como:

  • Capturar capturas de pantalla y generar archivos PDF de las páginas
  • Automatizar el envío de formularios
  • Realizar pruebas de la interfaz de usuario (hacer clic en botones, introducir datos con el teclado, etc.)
  • Rastrear una SPA y generar contenido prerenderizado (renderización del lado del servidor)

La mayoría de las acciones que se pueden realizar manualmente en el navegador también se pueden llevar a cabo con Puppeteer. Además, se pueden automatizar para ahorrar tiempo y centrarse en otras tareas.

Puppeteer también se diseñó para ser fácil de usar para los desarrolladores. Quienes estén familiarizados con otros marcos de pruebas populares, como Mocha, se sentirán como en casa con Puppeteer y encontrarán una comunidad activa que ofrece soporte para Puppeteer. Esto llevó a un enorme aumento de su popularidad entre los desarrolladores.

Por supuesto, Puppeteer no solo es adecuado para las pruebas. Al fin y al cabo, si puede hacer todo lo que hace un navegador estándar, entonces puede resultar extremadamente útil para los rastreadores web. Concretamente, puede ayudar a ejecutar código JavaScript para que el rastreador pueda acceder al HTML de la página e imitar el comportamiento normal de un usuario desplazándose por la página o haciendo clic en secciones aleatorias.

Estas funcionalidades tan necesarias convierten a los navegadores sin interfaz gráfica en un componente fundamental para cualquier herramienta comercial de extracción de datos y para todos los rastreadores web caseros, salvo los más sencillos.

Requisitos previos

Requisitos previos

En primer lugar, asegúrate de tener instaladas en tu equipo las versiones actualizadas de Node.js y Puppeteer. Si no es así, puedes seguir los pasos que se indican a continuación para instalar todos los requisitos previos.

Puedes descargar e instalar Node.js desde aquí. El gestor de paquetes predeterminado de Node, npm, viene preinstalado con Node.js.

Para instalar la biblioteca Puppeteer, puedes ejecutar el siguiente comando en el directorio raíz de tu proyecto:

npm install puppeteer
# or "yarn add puppeteer"

Ten en cuenta que, al instalar Puppeteer, también se descarga la última versión de Chromium, que garantiza el funcionamiento con la API.

Puppeteer en acción

Puppeteer en acción

Hay muchas cosas diferentes que puedes hacer con la biblioteca. Dado que nuestro enfoque principal es el web scraping, hablaremos de los casos de uso que más te interesarán si quieres extraer datos de la web.

Hacer una captura de pantalla

Hacer una captura de pantalla

Empecemos con un ejemplo básico. Escribiremos un script que capturará una captura de pantalla de un sitio web de nuestra elección.

Ten en cuenta que Puppeteer es una biblioteca basada en promesas (realiza llamadas asíncronas a la instancia de Chrome sin interfaz gráfica en segundo plano). Así que mantengamos el código limpio utilizando async/await.

En primer lugar, crea un nuevo archivo llamado index.js en el directorio raíz de tu proyecto.

Dentro de ese archivo, debemos definir una función asíncrona y envolver en ella todo el código de 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()

En primer lugar, se inicia una instancia del navegador utilizando el comando puppeteer.launch(). A continuación, creamos una nueva página utilizando la instancia del navegador. Para navegar hasta el sitio web deseado, podemos utilizar el método goto(), pasando la URL como parámetro. Para hacer una captura de pantalla, utilizaremos el método screenshot(). También debemos indicar la ubicación donde se guardará la imagen.

Ten en cuenta que Puppeteer establece un tamaño de página inicial de 800×600 píxeles, lo que define el tamaño de la captura de pantalla. Puedes personalizar el tamaño de la página utilizando el método setViewport().

No olvides cerrar la instancia del navegador. Después, solo tienes que ejecutar node index.js en la terminal.

¡Es así de sencillo! Ahora deberías ver un nuevo archivo llamado screenshot.png en la carpeta de tu proyecto.

Enviar un formulario

Enviar un formulario

Si, por alguna razón, el sitio web que quieres rastrear no muestra el contenido a menos que hayas iniciado sesión, puedes automatizar el proceso de inicio de sesión con Puppeteer.

En primer lugar, tenemos que inspeccionar el sitio web que estamos rastreando y encontrar los campos de inicio de sesión. Podemos hacerlo haciendo clic con el botón derecho del ratón sobre el elemento y seleccionando la opción Inspeccionar.

En mi caso, los campos de entrada se encuentran dentro de un formulario con la clase login-form. Podemos introducir las credenciales de inicio de sesión utilizando el método type().

Además, si quieres asegurarte de que realiza las acciones correctas, puedes añadir el parámetro headless y establecerlo en false al iniciar la instancia de Puppeteer. Entonces verás cómo Puppeteer realiza todo el proceso 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 un clic del ratón podemos utilizar el método click(). Después de hacer clic en el botón de inicio de sesión, debemos esperar a que se cargue la página. Podemos hacerlo con el método waitForNavigation().

Si hemos introducido las credenciales correctas, ¡ya deberíamos haber iniciado sesión!

Rastrear varias páginas

Rastrear varias páginas

Para este artículo, utilizaré el subreddit /r/learnprogramming. Queremos navegar hasta el sitio web y extraer el título y la URL de cada publicación. Para ello, utilizaremos el método evaluate().

El código debería tener este aspecto:

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 el método Inspect presentado anteriormente, podemos extraer todas las publicaciones apuntando al selector .thing. Iteramos a través de ellas y, para cada una, obtenemos la URL y el título y los añadimos a una matriz.

Una vez completado todo el proceso, podrás ver el resultado en tu consola.

Genial, hemos extraído la primera página. Pero, ¿cómo extraemos varias páginas de este subreddit?

Es más sencillo de lo que crees. Aquí está el 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()

Necesitamos una variable para saber cuántas páginas queremos rastrear y otra variable para la página actual. Mientras la página actual sea menor o igual al número de páginas que queremos rastrear, obtenemos la URL y el título de cada publicación de la página. Una vez recopilada cada página, concatenamos los nuevos resultados con los ya rastreados.

A continuación, hacemos clic en el botón de página siguiente y repetimos el proceso de rastreo hasta alcanzar el número deseado de páginas extraídas. También tenemos que incrementar la página actual después de cada página.

Una opción aún más sencilla

Una opción aún más sencilla

¡Enhorabuena! Has creado con éxito tu propio rastreador web con Puppeteer. ¡Espero que hayas disfrutado del tutorial!

Aun así, el script que hemos creado en esta guía no puede realizar tareas muy complejas. Le faltan algunos aspectos clave que hacen que el scraping web sea impecable. El uso de proxies móviles o residenciales y la resolución de CAPTCHAs son solo algunas de las funcionalidades que faltan.

Si buscas una forma más profesional de extraer datos, echa un vistazo a lo que WebScrapingAPI puede hacer y comprueba si se adapta a tus necesidades. Hay un paquete gratuito, así que lo único que tienes que invertir son 30 minutos de tu tiempo.

¡Feliz web scraping!

Acerca del autor
Gabriel Cioci, Desarrollador full-stack @ WebScrapingAPI
Gabriel CiociDesarrollador full-stack

Gabriel Cioci es desarrollador full stack en WebScrapingAPI, donde se encarga de crear y mantener los sitios web, el panel de usuario y los componentes principales de la plataforma destinados a los usuarios.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.