Volver al blog
Guías
Robert SfichiLast updated on Apr 28, 202615 min read

Web Scraping con JavaScript y Node.Js

Web Scraping con JavaScript y Node.Js

Seamos sinceros. A partir de ahora, el volumen de datos de Internet no hará más que crecer. La verdad es que no hay nada que podamos hacer al respecto. Aquí es donde entran en juego los rastreadores web.

En el siguiente artículo, te mostraremos cómo crear tu propio web scraper utilizando JavaScript como lenguaje de programación principal.

Entender el web scraping con JavaScript

Un web scraper es un programa que te ayuda a automatizar el tedioso proceso de recopilar datos útiles de sitios web de terceros. Por lo general, este procedimiento implica realizar una solicitud a una página web específica, leer el código HTML y desglosar ese código para recopilar algunos datos.

¿Por qué debería alguien extraer datos?

Imaginemos que quieres crear una plataforma de comparación de precios. Necesitas los precios de varios artículos de un par de tiendas online. Una herramienta de web scraping puede ayudarte a gestionar esto en un par de minutos.

Quizás estés intentando conseguir nuevos clientes potenciales para tu empresa o incluso encontrar los precios más favorables de vuelos u hoteles. Mientras rastreábamos la web, investigando para este artículo, nos topamos con Brisk Voyage.

Brisk Voyage es una aplicación web que ayuda a sus usuarios a encontrar viajes de fin de semana baratos de última hora. Mediante algún tipo de tecnología de web scraping, consiguen comprobar constantemente los precios de vuelos y hoteles. Cuando el web scraper encuentra un viaje que destaca por su bajo precio, el usuario recibe un correo electrónico con las instrucciones de reserva.

¿Para qué se utilizan los rastreadores web?

Los desarrolladores utilizan los web scrapers para todo tipo de obtención de datos, pero los casos más habituales son los siguientes:

  • Análisis de mercado
  • Comparación de precios
  • Generación de clientes potenciales
  • Investigación académica
  • Recopilación de conjuntos de datos de entrenamiento y prueba para el aprendizaje automático

¿Cuáles son los retos del web scraping con JavaScript y Node.js?

¿Conoces esas casillas que hay que marcar para demostrar que no eres un robot? Bueno, no siempre consiguen mantener alejados a los bots.

Pero la mayoría de las veces sí lo hacen, y cuando los motores de búsqueda descubren que estás intentando extraer datos de su sitio web sin permiso, restringen tu acceso.

Otro obstáculo al que se enfrentan los web scrapers son los cambios en la estructura de un sitio web. Un pequeño cambio en la estructura del sitio web puede hacernos perder mucho tiempo. Las herramientas de web scraping requieren actualizaciones frecuentes para adaptarse y hacer su trabajo.

Otro reto al que se enfrentan los rastreadores web es el llamado geobloqueo. En función de tu ubicación física, un sitio web puede bloquearte el acceso por completo si las solicitudes provienen de regiones poco fiables.

Para hacer frente a estos retos y ayudarte a centrarte en desarrollar tu producto, hemos creado WebScrapingAPI. Se trata de una API escalable de nivel empresarial y fácil de usar que te ayuda a recopilar y gestionar datos HTML. Nos obsesiona la velocidad, utilizamos una red global de proxies rotativos y ya contamos con más de 10 000 clientes que utilizan nuestros servicios. Si crees que no tienes tiempo para crear un scraper web desde cero, puedes probar WebScrapingAPI utilizando el plan gratuito.

API: la forma más fácil de hacer web scraping

La mayoría de las aplicaciones web proporcionan una API que permite a los usuarios acceder a sus datos de una forma predeterminada y organizada. El usuario realiza una solicitud a un punto final específico y la aplicación responde con todos los datos que el usuario ha solicitado específicamente. En la mayoría de los casos, los datos ya estarán formateados como un objeto JSON.

Al utilizar una interfaz de programación de aplicaciones, normalmente no tienes que preocuparte por los obstáculos mencionados anteriormente. Sea como sea, las API también pueden recibir actualizaciones. En esta situación, el usuario debe estar siempre atento a la API que está utilizando y actualizar el código en consecuencia para no perder su funcionalidad.

Además, la documentación de una API es muy importante. Si la funcionalidad de una API no está claramente documentada, el usuario acaba perdiendo mucho tiempo.

Comprender la web

Comprender bien Internet requiere muchos conocimientos. Repasemos una breve introducción a todos los términos que necesitas para entender mejor el web scraping.

HTTP o Protocolo de Transferencia de Hipertexto es la base de cualquier intercambio de datos en la web. Como su nombre indica, HTTP es una convención cliente-servidor. Un cliente HTTP, como un navegador web, abre una conexión con un servidor HTTP y envía un mensaje, del tipo: «¡Hola! ¿Qué tal? ¿Te importaría pasarme esas imágenes?». El servidor suele ofrecer una respuesta, en forma de código HTML, y cierra la conexión.

Supongamos que necesitas visitar Google. Si escribes la dirección en el navegador web y pulsas Intro, el cliente HTTP (el navegador) enviará el siguiente mensaje al servidor:

GET / HTTP/1.1
Host: google.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/web\p,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Connection: keep-aliveUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36

La primera línea del mensaje contiene el método de solicitud (GET), la ruta a la que hemos realizado la solicitud (en nuestro caso es simplemente «/», ya que solo hemos accedido a www.google.com), la versión del protocolo HTTP y varios encabezados, como Connection o User-Agent.

Hablemos de los campos de encabezado más importantes para el proceso:

  • Host: El nombre de dominio del servidor al que accediste después de escribir la dirección en el navegador web y pulsar Intro.
  • User-Agent: Aquí podemos ver detalles sobre el cliente que realizó la solicitud. Yo utilizo un MacBook, como se puede ver en la parte __(Macintosh; Intel Mac OS X 10_11_6)__, y Chrome como navegador web __(Chrome/56.0.2924.87)__.
  • Accept: Mediante este encabezado, el cliente limita al servidor para que solo le envíe determinados tipos de respuestas, como application/JSON o text/plain.
  • Referrer: Este campo de encabezado contiene la dirección de la página que realiza la solicitud. Los sitios web utilizan este encabezado para modificar su contenido en función de la procedencia del usuario.

Una respuesta del servidor puede tener este aspecto:

HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu) Content-Type: text/html; charset=utf-8 
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>The content of the document</body>
</html>

Como puedes ver, en la primera línea aparece el código de respuesta HTTP: **200 OK. Esto significa que la acción de scraping se ha realizado correctamente.

Ahora bien, si hubiéramos enviado la solicitud mediante un navegador web, este habría analizado el código HTML, obtenido todos los demás recursos como archivos CSS, JavaScript e imágenes, y habría renderizado la versión final de la página web. En los pasos siguientes, vamos a intentar automatizar este proceso.

Comprender el scraping web con Node.js

JavaScript se creó inicialmente para ayudar a sus usuarios a añadir contenido dinámico a los sitios web. Al principio, no podía interactuar directamente con un ordenador ni con sus datos. Cuando accedes a un sitio web, el navegador lee el JavaScript y lo convierte en unas pocas líneas de código que el ordenador puede procesar.

Presentamos Node.js, la herramienta que ayuda a que JavaScript se ejecute no solo del lado del cliente, sino también del lado del servidor. Node.js puede definirse como un JavaScript gratuito y de código abierto para la programación del lado del servidor. Ayuda a sus usuarios a crear y ejecutar aplicaciones de red rápidamente.

const http = require('http');
const port = 8000;
const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello world!');
});
server.listen(port, () => {
  console.log(`Server running on port 8000.`);
});

Si no tienes Node.js instalado, consulta el siguiente paso para ver las instrucciones. De lo contrario, crea un nuevo archivo index.js y ejecútalo escribiendo en un terminal node index.js, abre un navegador y navega a localhost:8000. Deberías ver la siguiente cadena: «Hello world!».

Herramientas necesarias

Chrome: sigue la guía de instalación que encontrarás aquí.

  • VSCode: puedes descargarlo desde esta página y seguir las instrucciones para instalarlo en tu dispositivo.
  • Node.js: antes de empezar a usar Axios, Cheerio o Puppeteer, debemos instalar Node.js y el Node Package Manager. La forma más sencilla de instalar Node.js y NPM es descargar uno de los instaladores de la página oficial de Node.js y ejecutarlo.

Una vez finalizada la instalación, puedes comprobar si Node.js está instalado ejecutando node -v y npm -v en una ventana de terminal. La versión debe ser superior a la v14.15.5. Si tienes problemas con este proceso, existe una forma alternativa de instalar Node.js.

Ahora, vamos a crear un nuevo proyecto NPM. Crea una nueva carpeta para el proyecto y ejecuta npm init -y. Ahora vamos a instalar las dependencias.

  • Axios: una biblioteca de JavaScript que se utiliza para realizar solicitudes HTTP desde Node.js. Ejecuta npm install axios en la carpeta recién creada.
  • Cheerio: una biblioteca de código abierto que nos ayuda a extraer información útil mediante el análisis de marcado y que proporciona una API para manipular los datos resultantes. Para utilizar Cheerio, puedes seleccionar etiquetas de un documento HTML utilizando selectores. Un selector tiene este aspecto: $("div"). Este selector específico nos ayuda a seleccionar todos los elementos <div> de una página.

Para instalar Cheerio, ejecuta npm install cheerio en la carpeta del proyecto.

  • Puppeteer: una biblioteca de Node.js que se utiliza para controlar Chrome o Chromium mediante una API de alto nivel.

Para utilizar Puppeteer, debes instalarlo mediante un comando similar: npm install puppeteer. Ten en cuenta que, al instalar este paquete, también se instalará una versión reciente de Chromium que garantiza la compatibilidad con tu versión de Puppeteer.

Inspección de la fuente de datos

En primer lugar, debes acceder al sitio web que deseas rastrear utilizando Chrome o cualquier otro navegador web. Para rastrear con éxito los datos que necesitas, debes comprender la estructura del sitio web.

Inspección del sitio web de destino

Una vez que hayas accedido al sitio web, utilízalo tal y como lo haría un usuario normal. Si has accedido al subreddit /r/dundermifflin, puedes consultar las publicaciones de la página principal haciendo clic en ellas, ver los comentarios y los votos positivos, e incluso ordenar las publicaciones por número de votos durante un periodo de tiempo específico.

Como puedes ver, el sitio web contiene una lista de publicaciones, y cada publicación tiene algunos votos positivos y algunos comentarios.

Se puede comprender gran parte de la información de un sitio web con solo mirar su URL. En este caso, https://www.old.reddit.com/r/DunderMifflin representa la URL base, la ruta que nos lleva a la comunidad de Reddit de «The Office». Al empezar a ordenar las publicaciones por número de votos, se puede ver que la URL base cambia a https://www.old.reddit.com/r/DunderMifflin/top/?t=year.

Los parámetros de consulta son extensiones de la URL que se utilizan para ayudar a definir contenido o acciones específicas en función de los datos que se pasan. En nuestro caso, «?t=year» representa el intervalo de tiempo seleccionado para el que queremos ver las publicaciones con más votos positivos.

Mientras sigas en este subreddit específico, la URL base seguirá siendo la misma. Lo único que cambiará son los parámetros de consulta. Podemos considerarlos como los filtros aplicados a la base de datos para recuperar los datos que queremos. Puedes cambiar el intervalo de tiempo para ver solo las publicaciones más votadas del último mes o de la última semana con solo modificar la URL.

Inspección con herramientas de desarrollador

En los siguientes pasos, aprenderás más sobre cómo se organiza la información en la página. Tendrás que hacer esto para comprender mejor qué podemos extraer realmente de nuestra fuente.

Las herramientas de desarrollo te ayudan a explorar de forma interactiva el Modelo de Objetos de Documento (DOM) del sitio web. Vamos a utilizar las herramientas de desarrollo de Chrome, pero puedes usar cualquier navegador web con el que te sientas cómodo. En Chrome, puedes abrirlas haciendo clic con el botón derecho en cualquier lugar de la página y seleccionando la opción «Inspeccionar».

En el nuevo menú que aparece en la pantalla, selecciona la pestaña «Elementos». Esto mostrará la estructura HTML interactiva del sitio web.

Puedes interactuar con el sitio web editando su estructura, expandiendo y colapsando elementos, o incluso eliminándolos. Ten en cuenta que estos cambios solo serán visibles para ti.

Las expresiones regulares y su función

Las expresiones regulares, también conocidas como RegEx, te ayudan a crear reglas que te permiten encontrar y gestionar diferentes cadenas de texto. Si alguna vez necesitas analizar grandes cantidades de información, dominar el mundo de las expresiones regulares puede ahorrarte mucho tiempo.

Cuando empiezas a usar expresiones regulares, pueden parecer un poco complicadas, pero la verdad es que son bastante fáciles de usar. Tomemos el siguiente ejemplo: \d. Al usar esta expresión, puedes seleccionar fácilmente cualquier dígito del 0 al 9. Por supuesto, hay otras mucho más complejas, como: ^(\(\d{3}\)|^\d{3}[.-]?)?\d{3}[.-]?\d{4}$. Esta expresión coincide con un número de teléfono, con o sin paréntesis alrededor del código de área, o con o sin puntos para separar los números.

Como puedes ver, las expresiones regulares son bastante fáciles de usar y pueden resultar muy potentes si dedicas el tiempo suficiente a dominarlas.

Comprender Cheerio.js

Una vez que hayas instalado correctamente todas las dependencias presentadas anteriormente y hayas inspeccionado el DOM utilizando las herramientas de desarrollo, puedes pasar al scraping propiamente dicho.

Una cosa que debes tener en cuenta es que, si la página que intentas extraer es una SPA (aplicación de página única), puede que Cheerio no sea la mejor solución. La razón es que Cheerio no puede «pensar» realmente como un navegador web. Por eso, en los siguientes pasos vamos a utilizar Puppeteer. Pero hasta entonces, veamos lo potente que es Cheerio.

Para probar la funcionalidad de Cheerio, intentemos recopilar todos los títulos de las publicaciones del subreddit presentado anteriormente: /r/dundermifflin.

Creemos un nuevo archivo llamado index.js y escribamos o simplemente copiemos las siguientes líneas:

const axios = require("axios");
const cheerio = require("cheerio");
const fetchTitles = async () => {
	try {
		const response = await axios.get('https://old.reddit.com/r/DunderMifflin/');
                const html = response.data;
		const $ = cheerio.load(html);
		const titles = [];
		$('div > p.title > a').each((_idx, el) => {
			const title = $(el).text()
			titles.push(title)
		});
		return titles;
	} catch (error) {
		throw error;
	}};
fetchTitles().then((titles) => console.log(titles));

Para entender mejor el código escrito anteriormente, vamos a explicar qué hace la función asíncrona fetchTitles():

En primer lugar, realizamos una solicitud GET al antiguo sitio web de Reddit utilizando la biblioteca Axios. El resultado de esa solicitud es cargado por Cheerio en la línea 10. Usando las herramientas de desarrollador, hemos descubierto que los elementos que contienen la información deseada son un par de etiquetas de anclaje. Para asegurarnos de que solo seleccionamos las etiquetas de anclaje que contienen el título de la publicación, también vamos a seleccionar sus elementos padres utilizando el siguiente selector: $('div > p.title &g;t; a')

Para obtener cada título individualmente y no solo un gran bloque de letras sin sentido, tenemos que recorrer cada publicación utilizando la función each(). Por último, llamar a text() en cada elemento me devolverá el título de esa publicación específica.

Para ejecutarlo, solo tienes que escribir node index.js en la terminal y pulsar Intro. Deberías ver una matriz que contiene todos los títulos de las entradas.

DOM para NodeJS

Dado que el DOM de una página web no está disponible directamente para Node.js, podemos utilizar JSDOM. Según su documentación, JSDOM es una implementación en JavaScript puro de muchos estándares web, en particular los estándares DOM y HTML de WHATWG, para su uso con Node.js.

En otras palabras, utilizando JSDOM, podemos crear un DOM y manipularlo utilizando los mismos métodos que usaríamos para manipular el del navegador web.

JSDOM te permite interactuar con un sitio web que necesites rastrear. Si estás familiarizado con la manipulación del DOM del navegador web, comprender la funcionalidad de JSDOM no te supondrá mucho esfuerzo.

Para entender mejor cómo funciona JSDOM, instalémoslo, creemos un nuevo archivo index.js y escribamos o copiemos el siguiente código:

const { JSDOM } = require('jsdom')
const { document } = new JSDOM(
  '<h1 class="string">Dunder mifflin, the people person\'s paper people!</h2>'
).window
const string = document.querySelector('.string')
console.log(string.innerHTML)
string.textContent = 'Hello world'
console.log(string.innerHTML)

Como puedes ver, JSDOM crea un nuevo Modelo de Objetos de Documento (DOM) que se puede manipular utilizando el mismo método que usamos para manipular el DOM del navegador. En la línea 3 se crea un nuevo elemento h1 en el DOM. Utilizando la clase atribuida al encabezado, seleccionamos el elemento en la línea 7 y cambiamos su contenido en la línea 10. Puedes ver la diferencia imprimiendo el elemento DOM antes y después del cambio.

Para ejecutarlo, abre un nuevo terminal, escribe node index.js y pulsa Intro.

Por supuesto, puedes realizar acciones mucho más complejas con JSDOM, como abrir una página web e interactuar con ella, rellenar formularios y hacer clic en botones.

Por lo que vale, JSDOM es una buena opción, pero Puppeteer ha ganado mucha popularidad en los últimos años.

Entender Puppeteer: cómo desentrañar páginas JavaScript

Con Puppeteer, puedes hacer casi todo lo que se puede hacer manualmente en un navegador web, como rellenar un formulario, generar capturas de pantalla de páginas o automatizar pruebas de interfaz de usuario.

Intentemos comprender mejor su funcionalidad haciendo una captura de pantalla de la comunidad de Reddit /r/dundermifflin. Si ya has instalado la dependencia, pasa al siguiente paso. Si no es así, ejecuta npm i puppeteer en la carpeta del proyecto. Ahora, crea un nuevo archivo index.js y escribe o copia el siguiente código:

const puppeteer = require('puppeteer')
async function takeScreenshot() {
	try {
		const URL = 'https://www.old.reddit.com/r/dundermifflin/'
		const browser = await puppeteer.launch()
		const page = await browser.newPage()
		await page.goto(URL)
		await page.pdf({ path: 'page.pdf' })
		await page.screenshot({ path: 'screenshot.png' })
		await browser.close()
	} catch (error) {
		console.error(error)
	}
}
takeScreenshot()

Hemos creado la función asíncrona takeScreenshot().

Como puedes ver, primero se inicia una instancia del navegador utilizando el comando puppeteer.launch(). A continuación, creamos una nueva página y, al llamar a la función goto() utilizando la URL como parámetro, la página creada anteriormente se dirigirá a esa URL específica. Los métodos pdf() y screenshot() nos ayudan a crear un nuevo archivo PDF y una imagen que contiene la página web como componente visual.

Por último, la instancia del navegador se cierra en la línea 13. Para ejecutarlo, escribe node index.js en la terminal y pulsa Intro. Deberías ver dos archivos nuevos en la carpeta projects llamados page.pdf y screenshot.png.

Alternativa a Puppeteer

Si no te sientes cómodo utilizando Puppeteer, siempre puedes recurrir a una alternativa como NightwatchJS, NightmareJS o CasperJS.

Tomemos Nightmare como ejemplo. Como utiliza Electrons en lugar de Chromium, el tamaño del paquete es un poco menor. Nightmare se puede instalar ejecutando el comando npm install nightmare. Intentaremos replicar el proceso que antes funcionó para hacer una captura de pantalla de la página utilizando Nightmare en lugar de Puppeteer.

Creemos un nuevo archivo index.js y escribamos o copiemos el siguiente código:

const Nightmare = require('nightmare')
const nightmare = new Nightmare()
return nightmare.goto('https://www.old.reddit.com/r/dundermifflin')
	.screenshot('./nightmare-screenshot.png')
 	.end()
	.then(() => {
		console.log('Done!')
	})
	.catch((err) => {
		console.error(err)
	})

Como puedes ver en la línea 2, creamos una nueva instancia de Nightmare, dirigimos el navegador a la página web de la que queremos hacer una captura de pantalla, tomamos y guardamos la captura en la línea 5 y terminamos la sesión de Nightmare en la línea 6.

Para ejecutarlo, escribe node index.js en la terminal y pulsa Intro. Deberías ver dos archivos nuevos, nightmare-screenshot.png, en la carpeta de proyectos.

Conclusiones principales

Si sigues aquí, ¡enhorabuena! Ya tienes toda la información que necesitas para crear tu propio rastreador web. Dediquemos un momento a resumir lo que has aprendido hasta ahora:

  • Un rastreador web es un programa que te ayuda a automatizar el tedioso proceso de recopilar datos útiles de sitios web de terceros.
  • La gente utiliza los web scrapers para todo tipo de obtención de datos: análisis de mercado, comparación de precios o generación de clientes potenciales.
  • Los clientes HTTP, como los navegadores web, te ayudan a realizar solicitudes a un servidor y a recibir una respuesta.
  • JavaScript se creó inicialmente para ayudar a sus usuarios a añadir contenido dinámico a los sitios web. Node.js es una herramienta que permite que JavaScript se ejecute no solo en el lado del cliente, sino también en el lado del servidor.
  • Cheerio es una biblioteca de código abierto que nos ayuda a extraer información útil mediante el análisis de HTML y proporciona una API para manipular los datos resultantes.
  • Puppeteer es una biblioteca de Node.js que se utiliza para controlar Chrome o Chromium mediante una API de alto nivel. Gracias a ella, puedes realizar la mayoría de las acciones que se pueden hacer manualmente en un navegador web, como rellenar un formulario, generar capturas de pantalla de páginas o automatizar tareas.
  • Se puede comprender gran parte de los datos de un sitio web con solo mirar su URL.
  • Las herramientas de desarrollador te ayudan a explorar de forma interactiva el Modelo de Objetos de Documento (DOM) del sitio web.
  • Las expresiones regulares te ayudan a crear reglas que te permiten encontrar y gestionar diferentes cadenas.
  • JSDOM es una herramienta que crea un nuevo Modelo de Objetos de Documento que se puede manipular utilizando el mismo método que se usa para manipular el DOM del navegador.

Esperamos que las instrucciones hayan sido claras y que hayas conseguido toda la información necesaria para tu próximo proyecto. Si sigues sin querer hacerlo tú mismo, siempre puedes probar WebScrapingAPI.

¡Gracias por seguir hasta el final!

Acerca del autor
Robert Sfichi, Desarrollador full-stack @ WebScrapingAPI
Robert SfichiDesarrollador full-stack

Robert Sfichi forma parte del equipo de WebScrapingAPI, donde contribuye al desarrollo del producto y ayuda a crear soluciones fiables que dan soporte a la plataforma y a sus 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.