Web scraping con javascript y nodejs

En un Internet en donde todo está conectado la información fluye de un punto a otro sin dificultad. Lo vemos cada día al iniciar nuestros dispositivos. De pronto, casi como por arte de magia, ahí están nuestros correos, notificaciones, información financiera, estado del tiempo, y si hoy la ruta que solemos hacer para llegar al trabajo tendrá más tráfico del habitual.

Esta magia de la que hablaba, en donde múltiples aplicaciones y servicios se interconectan entre sí para obtener nuestra información deseada, tiene nombre, API REST. Gracias a las API es posible todo esto, pero no siempre es posible o no está disponible para nosotros que somos viles usuarios mortales y no tenemos suficiente nivel de permisos o dinero para invertir para hacer uso de ellas, algunas API REST son de pago o tienen limitaciones de uso que hacen muy difícil consumirla de manera programada.

Pero esto no es algo nuevo. Mucho antes de que existieran las API REST, ya hacíamos “corta y pega” de la información contenida en la web para incluirla en nuestros proyectos. En este artículo no hablaremos de “cortar y pegar”, sino de una técnica alternativa llamada web scraping. Para ello crearemos una pieza de código muy sencilla para extraer información de varios sitios web o en otras palabras, básicamente similar a una persona navegando en la web.

Introducción:

Una de las cosas que siempre me llamaba la atención en mis tiempos de estudiante era ver como muchas de las visitas que llegaban a mi web no eran personas. En realidad muchos de mis visitantes eran un ejército de crawlers, spiders, scrapers y bots que llegaban, hacían lo que venían a hacer y ya.

Os juro que cuando no tenía ni idea de esto que alguien en la lejana Rusia me estaba atacando. Pero en realidad en la mayoría de los casos solo me estaban indexando o “scrapeando”. Luego ya entrando más en detalle pues descubrí que así funcionaban los buscadores de la época como Yahoo, Altavista o Google. Estos motores de búsqueda utilizan esta técnica para indexar toda la web y así mostrarlos en sus resultados de búsqueda.

El web scraping es usado en infinidades de tareas en el internet. Son llamados de diferentes formas dependiendo de su función (crawlers, spiders, scrapers, bots), estos son los responsables de generar el mayor tráfico en el internet.

Pero vayamos a lo importante. Ya entonces pero mucho más hoy, la automatización de tareas repetitivas en la web debe ser una prioridad para evitar invertir demasiado tiempo en nuestro día a día. Por ejemplo, imagina que tienes que recopilar información de diferentes fuentes, no tienes acceso a sus API y tienes que pasarte el fin de semana preparando ese informe que no puede esperar. Pero espera, que ese informe es semanal… ¿Qué vas a hacer? ¿En serio vas a perder horas de tu fin de semana haciendo lo mismo una y otra vez?

Usando técnicas de Web Scraping vamos a poder hacer la recopilación de información procedente de diferentes sitios, organizarla y mostrarla de manera estructurada y repetir el proceso una y otra vez sin soltar las manos del “cubata”. Vale, esta ha sido una broma fácil. Pero continuemos.

Ahora bien, el web scraping dada su naturaleza, puede ir en contra de los términos legales y el modo de usar la información de algunos sitios web. Sugiero informarte bien sobre este tema antes de empezar a realizar tus programas de scraping.

Librerías necesarias para hacer web scraping

Lo primero que necesitamos es una librería que pueda hacer peticiones mediante el protocolo HTTP, que es el usado por los sitios web. Aquí existen dos variantes a tener en cuenta.

Quizá la más popular es GOT. Esta librería nos dará el html devuelto por del servidor pero ojo, muchos sitios web en la actualidad usan JavaScript para dar forma a la web que ves, ¿te suena AJAX? pues eso puede ser un problema si no podemos simular “presencia humana” ya que la información no estará ahí cuando nuestra herramienta pase a buscar “la mercancía”.

Sí, ya estamos hablando como mafiosos. Pero es que estamos haciendo trampas. Así que vamos a detenernos 1 minuto aquí para colocarnos el parche en el ojo y nuestro gorro pirata.

Continuamos. Así, si necesitamos el html renderizado por el javascript y por el servidor necesitamos un headless browser.

Existen varias alternativas. La más popular y recomendada es puppeteer. un headless browser basado en Chromium, capaz de obtener el html generado por el servidor y por el javascript.

Y ya por último, necesitaremos una librería para procesar el html que devuelva el sitio web, para lo cual recomiendo usar jsdom.

Ejemplo práctico, extrayendo el título de los resultados orgánicos de Google

En este sencillo ejemplo buscaremos en Google resultados de libros de web scraping y mostraremos los títulos por consola.

Dentro de un directorio iniciamos un proyecto npm el comando con npm init --yes. Luego instalamos nuestras dependencias con el comando npm install --save puppeteer jsdom. Con esto tenemos lo necesario para crear nuestro primer scraper.

Creamos un archivo llamado google-scraper.js y dentro escribimos el siguiente código.

const puppeteer = require('puppeteer');
const jsdom = require('jsdom');

(async () => {
  try {
    // Abrimos una instancia del puppeteer y accedemos a la url de google
    const browser = await puppeteer.launch() ;
    const page = await browser.newPage();
    const response = await page.goto('https://www.google.com/search?q=web+scraping+libros');
    const body = await response.text();

    // Creamos una instancia del resultado devuelto por puppeter para parsearlo con jsdom
    const { window: { document } } = new jsdom.JSDOM(body);

    // Seleccionamos los títulos y lo mostramos en consola
    document.querySelectorAll('.g h3')
      .forEach(element => console.log(element.textContent));

    // Cerramos el puppeteer
    await browser.close();
  } catch (error) {
    console.error(error);
  }
})();

 

Si conoces cómo funciona JavaScript, seguro que async y await te resultan familiares. Básicamente lo que estamos haciendo es trabajar con promesas. Debido a que la ejecución del script y la obtención de resultados es el resultado de una operación asíncrona, con esto nos aseguramos que el proceso se realizará con éxito.

Una Promesa es un proxy para un valor no necesariamente conocido en el momento que es creada la promesa. Permite asociar manejadores que actuarán asincrónicamente sobre un eventual valor en caso de éxito, o la razón de falla en caso de una falla. Esto permite que métodos asíncronos devuelvan valores como si fueran síncronos: en vez de inmediatamente retornar el valor final, el método asíncrono devuelve una promesa de suministrar el valor en algún momento en el futuro.

Una vez terminado, ejecutamos el comando node google-scraper.js para ejecutar el scraper. Si todo sale correcto, debería mostrar un listado de todos los títulos de los resultados orgánicos de libros de web scraping en la primera página de Google.

Ahora puedes imaginar el potencial. Usando node js y javascript podemos automatizar tareas y ver los resultados en pocos minutos mientras disfrutamos de nuestra jarra de Grog.

<div class="tenor-gif-embed" data-postid="12107963" data-share-method="host" data-aspect-ratio="1.86916" data-width="100%"><a href="https://tenor.com/view/pirate-ship-arr-monkey-island-grog-rum-gif-12107963">Pirate Ship Arr GIF</a>from <a href="https://tenor.com/search/pirate+ship-gifs">Pirate Ship GIFs</a></div> <script type="text/javascript" async src="https://tenor.com/embed.js"></script>

Conclusión:

Espero que este artículo te ayude a entender que es el web scraping y cómo funciona con un ejemplo en javascript y nodejs. Las posibilidades son muchas y variadas. Invirtiendo unos minutos es posible encontrar múltiples ejemplos para mejorar nuestro proyecto. Aunque si quieres profundizar todavía más te recomiendo la lectura de un buen libro sobre Web Scraping o revisar la documentación oficial de Puppeteer para obtener más información sobre las posibilidades que ofrece esta librería.

 

 

Tags

He leído y acepto la política de privacidad
Acepto recibir emails sobre actividades de recruiting NTT DATA