Web Scraping con Node.js

Por definición, web scraping significa obtener información útil de las páginas web. El proceso debería eliminar la molestia de tener que navegar por las páginas manualmente, ser automático...

Introducción

Por definición, web scraping significa obtener información útil de las páginas web. El proceso debería eliminar la molestia de tener que navegar por las páginas manualmente, estar automatizado y permitir recopilar y clasificar la información que le interesa mediante programación.

Nodo.js es una gran herramienta para el web scraping. Permite implementar rutinas de web scraping en un par de líneas de código usando el módulo de código abierto provisto por npm - el Node Package Manager.

Los pasos principales del web scraping

Como ya hemos definido, el web scraping no es más que automatizar la navegación manual y la recopilación de información de sitios web específicos en su navegador web preferido.

Este proceso consta de 3 pasos principales:

  • Obtener el código fuente HTML del sitio web
  • Dar sentido al contenido HTML, encontrar la información que nos interesa y extraerla
  • Mover la información descubierta al almacenamiento de su elección (archivo de texto, base de datos, etc.)

Los pasos primero y final suelen ser prácticamente los mismos, según los requisitos de su aplicación. Sin embargo, dar sentido al contenido HTML requiere que escribas un código específico para cada sitio web que quieras raspar.

Precaución

Dependiendo de su uso de estas técnicas y tecnologías, su aplicación podría estar realizando acciones ilegales

Hay algunos casos en los que desearía tener cuidado con:

  • DoS - A Ataque de denegación de servicio prácticamente se basa en enviar tantas solicitudes al servidor que simplemente puede' t manejar más. Entonces se denegarían todas las nuevas solicitudes entrantes. Si raspa un sitio web con demasiada frecuencia, puede considerarse un ataque DoS.
  • Términos de servicio - Muchos sitios web, y casi todos los sitios web más grandes, establecen claramente que el web scraping en sus plataformas está prohibido. Si mucha gente extrajera estos sitios web, terminaría siendo un ataque DDoS, que en sí mismo es ilegal.
  • Software abusivo: muchas herramientas y marcos en línea ofrecen una gran variedad de herramientas y funcionalidades. Algunos permiten a los usuarios completar formularios, enviar datos, cargar y descargar archivos, etc. [CAPTCHA] (https://en.wikipedia.org/wiki/CAPTCHA) se usa para combatir esto, sin embargo, incluso esto se puede superar con un bot .

Algoritmo de extracción web manual

Como ejemplo, buscaremos Páginas Amarillas para empresas que brindan servicios de impresión en Nueva York.

En primer lugar, definamos nuestra tarea y el resultado deseado:

Produzca una lista de las empresas que brindan servicios de impresión en Nueva York en forma de un archivo ".CSV" que debe tener el nombre de la empresa, correo electrónico, teléfono y columnas de enlace que describan a cada empresa.

Así es como lo haríamos manualmente:

  1. Navegue por nuestro navegador al enlace apropiado y coloque "impresión" y "Nueva York" en los campos de búsqueda y ejecute la búsqueda
  2. Seleccione y almacene el nombre de la primera empresa en la lista
  3. Guarda el enlace a la página de la empresa y síguelo
  4. Encuentra una dirección de correo electrónico y guárdala
  5. Escriba los valores almacenados en un archivo ".CSV", ya sea usando un editor de texto u otra herramienta para editar tablas como Excel o Google Sheets

Repetir estos pasos varias veces nos dará una tabla llena de detalles de la empresa.

Automatización del proceso con Web Scraping

Para automatizar el proceso, debemos seguir los mismos pasos programáticamente.

Configuración del entorno de desarrollo {#configuración del entorno de desarrollo}

Usaremos Node.js y npm para desarrollar este proyecto de muestra. Así que asegúrese de que esas herramientas estén instaladas en su máquina y comencemos ejecutando el siguiente comando en un directorio vacío de su elección, seguido de la creación de una página index.js vacía que contendrá nuestro código:

1
$ npm init

El siguiente paso es instalar los módulos necesarios desde npm.

Del algoritmo manual descrito anteriormente, vemos que necesitaremos algo para obtener el código fuente HTML, analizar el contenido y darle sentido y luego escribir la matriz de objetos JavaScript en el archivo ".CSV". :

1
$ npm install --save request request-promise cheerio objects-to-csv

Ejecutar la línea anterior en la terminal instalará los módulos necesarios en el directorio node_modules y los guardará como dependencias en el archivo package.json.

Recuperando información {#recuperando información}

Una vez que haya terminado con toda la preparación, puede abrir el archivo index.js en su editor de texto favorito y solicitar los módulos que acabamos de instalar:

1
2
3
const rp = require('request-promise');
const otcsv = require('objects-to-csv');
const cheerio = require('cheerio');

Completar este paso en el algoritmo manual nos dará el enlace, que dividiremos en dos partes y agregaremos a index.js justo después de los módulos:

1
2
const baseURL = 'https://www.yellowpages.com';
const searchURL = '/search?search_terms=printing&geo_location_terms=New+York%2C+NY';

Luego, debemos escribir una función que devuelva la matriz de objetos de JavaScript que representan a las empresas de la descripción de la tarea.

Para poder traducir el algoritmo manual a código, primero tendremos que hacer un trabajo manual usando la herramienta inspector de nuestro navegador web.

Tendremos que encontrar los elementos HTML específicos que contengan la información que nos interesa. En nuestro caso, el nombre de la empresa podría encontrarse en un elemento como:

1
<a class="business-name" href="/new-york-ny/mip/global-copy-2988131?lid=1000106255864" itemprop="name">Global Copy</a>

web_scraping_with_node_js

Que es una etiqueta <a> con la clase nombre comercial, que contiene el nombre de la empresa y una propiedad href que contiene un enlace a la página individual de la empresa. Ambos nos serán útiles en el futuro.

Siguiendo el enlace a la página de la empresa, necesitaremos encontrar los dos datos restantes: el teléfono y el correo electrónico. Se ubican bajo las etiquetas <p> con la clase teléfono y la etiqueta <a> con la clase email-business.

web_scraping_with_node_js

web_scraping_with_node_js

Tome nota de que para obtener el teléfono, necesitaremos el valor almacenado dentro de la etiqueta y para recibir un correo electrónico, necesitaremos una propiedad href de la etiqueta <a>.

Veamos cómo se verá el algoritmo manual cuando intentemos implementarlo mediante programación:

  1. Obtenga el código fuente HTML de la página que estamos buscando raspar usando el módulo request-promise y alimentándolo con un enlace que obtuvimos en el primer paso de nuestro algoritmo manual
  2. Asigne la matriz de nombres de empresas en el HTML original a una matriz de objetos con las propiedades nombre, enlace, teléfono y correo electrónico.
  3. Convierta la matriz resultante en un archivo CSV

Así es como se verá este algoritmo cuando se implemente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const getCompanies = async () => {
  const html = await rp(baseURL + searchURL);
  const businessMap = cheerio('a.business-name', html).map(async (i, e) => {
    const link = baseURL + e.attribs.href;
    const innerHtml = await rp(link);
    const emailAddress = cheerio('a.email-business', innerHtml).prop('href');
    const name = e.children[0].data;
    const phone = cheerio('p.phone', innerHtml).text();

    return {
      emailAddress,
      link,
      name,
      phone,
    }
  }).get();
  return Promise.all(businessMap);
};

Sigue las reglas que configuramos anteriormente y devuelve una Promesa que se resuelve en una matriz de objetos JavaScript:

1
2
3
4
5
6
{
  "emailAddress": "mailto:[correo electrónico protegido]",
  "link": "https://www.yellowpages.com/new-york-ny/mip/global-copy-2988131?lid=1000106255864",
  "name": "Global Copy",
  "phone": "(212) 222-2679"
}

Promesa

En caso de que no esté familiarizado con los conceptos básicos de la programación asíncrona en JavaScript moderno, aquí hay una breve introducción a Promises.

Una Promesa es un tipo especial que actúa como un marcador de posición para el valor. Podría estar en un par de estados:

  • pendiente
  • cumplido
  • rechazado

Sin entrar en demasiados detalles al respecto, solo debe saber que las funciones que devuelven promesas, no devuelven los valores reales. Para obtener acceso al resultado de la Promesa o al valor de resolución, debe escribir otra función, que debe pasarse al bloque ’entonces’ y esperar el valor con el que se resolverá la Promesa. Si ocurre algún error dentro de la Promesa mientras está pendiente, pasará al estado rechazado con la posibilidad de manejar el error en el bloque catch.

Almacenamiento de datos y toques finales {#almacenamiento de datos y toques finales}

Aunque el resultado parece bastante bueno, observar más de cerca la matriz de empresas nos muestra que el correo electrónico tiene un prefijo mailto: innecesario y, a veces, faltan los correos electrónicos y los nombres de las empresas:

1
2
3
4
5
6
{
  "emailAddress": undefined,
  "link": "https://www.yellowpages.com/new-york-ny/mip/apm-451909424?lid=451909424",
  "name": undefined,
  "phone": "(212) 856-9800"
}

Al volver a la herramienta de inspección, vemos que el nombre de la empresa también se puede encontrar en la página interna de la empresa dentro de una etiqueta <h1>.

A veces faltan los correos electrónicos de ciertas empresas y no podemos hacer nada al respecto.

El prefijo mailto: podría eliminarse usando una función reemplazar.

Aquí están los ajustes que debe hacer a su código:

1
2
3
4
5
...
    const name = e.children[0].data || cheerio('h1', innerHtml).text();
...
    emailAddress: emailAddress ? emailAddress.replace('mailto:', '') : '',
...

Ahora que hemos extraído todos los datos necesarios de la página web y tenemos una matriz limpia de objetos JavaScript, podemos preparar el archivo ".CSV" requerido por nuestra definición de tarea:

1
2
3
4
5
6
getCompanies()
  .then(result => {
    const transformed = new otcsv(result);
    return transformed.toDisk('./output.csv');
  })
  .then(() => console.log('SUCCESSFULLY COMPLETED THE WEB SCRAPING SAMPLE'));

La función getCompanies devuelve una promesa que se resuelve en una matriz de objetos preparados para escribirse en el archivo CSV, lo que se hace en el primer bloque then. El segundo se resuelve cuando el archivo CSV se escribe con éxito en el sistema de archivos, completando así la tarea.

Agregando este fragmento de código a nuestro archivo index.js y ejecutándolo con:

1
$ node index.js

Deberíamos obtener un archivo output.csv directamente en nuestro directorio de trabajo. La tabla representada por este archivo .CSV contiene 4 columnas: dirección de correo electrónico, enlace, nombre, teléfono, y cada fila describe una sola empresa.

Conclusión

En esencia, web scraping es navegar por páginas web, recoger información útil según la tarea y almacenarla en algún lugar, todo lo cual se hace mediante programación. Para poder hacer esto con el código, este proceso debe realizarse primero manualmente utilizando una herramienta de “inspector” del navegador o analizando el contenido HTML sin formato de la página web de destino.

Node.js proporciona herramientas confiables y simples para hacer que el web scraping sea una tarea sencilla que podría ahorrarle mucho tiempo en comparación con el procesamiento manual de los enlaces.

Aunque puede parecer tentador automatizar todas sus tareas diarias de esta manera, tenga cuidado cuando se trata de usar estas herramientas, porque es fácil violar los términos de servicio de un sitio web si no lo ha leído por completo. , o incluso simplemente generando una gran cantidad de tráfico con su raspador.