Volver al blog
Guías
Mihai MaximLast updated on Mar 31, 20268 min read

Cómo extraer datos de una tabla HTML en JavaScript

Cómo extraer datos de una tabla HTML en JavaScript

Saber cómo extraer datos de tablas HTML con JavaScript puede ser una habilidad fundamental a la hora de trabajar con datos tabulares que se muestran en la web. Los sitios web suelen mostrar información importante, como detalles de productos, precios, niveles de inventario y datos financieros, en tablas. Ser capaz de extraer esta información resulta extremadamente útil a la hora de recopilar datos para todo tipo de tareas de análisis. En este artículo, profundizaremos en las tablas HTML y crearemos un programa sencillo pero potente para extraer datos de ellas y exportarlos a un archivo CSV o JSON. Utilizaremos Node.js y cheerio para que el proceso sea muy sencillo.

Comprender la estructura de una tabla HTML

Las tablas HTML son una herramienta potente para marcar datos tabulares estructurados y mostrarlos de una forma que resulte fácil de leer y comprender para los usuarios. Las tablas se componen de datos organizados en filas y columnas, y el HTML proporciona varios elementos diferentes para definir y estructurar estos datos. Una tabla debe incluir al menos los siguientes elementos: <table>, <tr> (fila de la tabla) y <td> (datos de la tabla). Para añadir estructura y valor semántico, las tablas también pueden incluir el elemento <th> (encabezado de tabla), así como los elementos <thead>, <tbody> y <tfoot>.

Exploremos las etiquetas con la ayuda de un pequeño ejemplo.

Fíjate en cómo la segunda tabla utiliza una sintaxis más específica

La etiqueta <thead> aplicará una fuente en negrita a las celdas «Fruit» y «Color» de la segunda tabla. Aparte de eso, se puede ver cómo ambas sintaxis logran la misma organización de los datos.

Al extraer tablas de la web, es importante tener en cuenta que puedes encontrarte con tablas escritas con distintos grados de especificidad semántica. En otras palabras, algunas tablas pueden incluir etiquetas HTML más detalladas y descriptivas, mientras que otras pueden utilizar una sintaxis más simple y menos descriptiva.

Extracción de tablas HTML con Node.js y cheerio

¡Bienvenido a la parte divertida! Hemos aprendido sobre la estructura y la finalidad de las tablas HTML, y ahora es el momento de poner en práctica esos conocimientos con un ejercicio práctico. Nuestro objetivo para este tutorial es la tabla de los artistas más vendidos de todos los tiempos que se encuentra en https://chartmasters.org/best-selling-artists-of-all-time/. Empezaremos por configurar nuestro entorno de trabajo e instalar las bibliotecas necesarias. A continuación, exploraremos el sitio web de nuestro objetivo y crearemos algunos selectores para extraer los datos que se encuentran en la tabla. Después, escribiremos el código para extraer los datos y, por último, los exportaremos a diferentes formatos, como CSV y JSON.

Configuración del entorno de trabajo

¡Muy bien, empecemos con nuestro nuevo proyecto! Antes de empezar, asegúrate de tener instalado Node.js. Puedes descargarlo desde https://nodejs.org/en/.

Ahora abre tu editor de código favorito, abre el directorio de tu proyecto y ejecuta (en la terminal):

npm init -y

Esto inicializará un nuevo proyecto y creará un archivo package.json predeterminado.

{

  "name": "html_table_scraper", // the name of your project folder

  "version": "1.0.0",

  "description": "",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "keywords": [],

  "author": "",

  "license": "ISC"

}

Para simplificar las cosas, importaremos nuestros módulos con «require». Pero si quieres importar módulos utilizando la instrucción «import», añade esto a tu archivo package.json:


"type": "module",

// this will enable you to use the import statement

// ex: import * as cheerio from 'cheerio';

La opción «main»: «index.js» especifica el nombre del archivo que es el punto de entrada de nuestro programa. Dicho esto, ya puedes crear un archivo index.js vacío.

Usaremos la biblioteca cheerio para analizar el HTML de nuestro sitio web de destino. Puedes instalarla con:

npm install cheerio

Ahora abre el archivo index.js e inclúyelo como módulo:

const cheerio = require('cheerio');

El entorno de trabajo básico ya está configurado. En el siguiente capítulo, exploraremos la estructura de la tabla de los artistas más vendidos de todos los tiempos.

Probar el sitio web de destino con DevTools

Al inspeccionar la pestaña «Elementos» de las Herramientas de desarrollo, podemos extraer información valiosa sobre la estructura de la tabla:

La tabla está almacenada en formato <thead>, <tbody>.

A todos los elementos de la tabla se les asignan identificadores descriptivos, clases y roles.

En el contexto de un navegador, tienes acceso directo al HTML de una página web. Esto significa que puedes utilizar funciones de JavaScript como getElementsByTagName o querySelector para extraer datos del HTML.

Teniendo esto en cuenta, podemos utilizar la consola de las Herramientas de desarrollo para probar algunos selectores.

Extraigamos los nombres de los encabezados utilizando el atributo role="columnheader"

Ahora extraigamos los datos de la primera fila utilizando los atributos role="cell" y role="row":

Como puedes ver:

Podemos utilizar «[role=columnheader]» para seleccionar todos los elementos de encabezado.

Podemos usar «tbody [role=row]» para seleccionar todos los elementos de fila.

Para cada fila, podemos usar «[role=cell]» para seleccionar sus celdas.

Hay que tener en cuenta que la celda PIC contiene una imagen y debemos escribir una regla especial para extraer su URL.

Implementación de un rastreador de tablas HTML

Ahora es el momento de avanzar un poco más utilizando Node.js y cheerio.

Para obtener el HTML de un sitio web en un proyecto de Node.js, tendrás que realizar una solicitud fetch al sitio. Esto devuelve el HTML como una cadena, lo que significa que no puedes usar funciones DOM de JavaScript para extraer datos. Ahí es donde entra en juego cheerio. Cheerio es una biblioteca que te permite analizar y manipular la cadena HTML como si estuvieras en el contexto de un navegador. Esto significa que puedes utilizar selectores CSS habituales para extraer datos del HTML, tal y como lo harías en un navegador.

También es importante tener en cuenta que el HTML devuelto por una solicitud fetch puede ser diferente del HTML que ves en el navegador. Esto se debe a que el navegador ejecuta JavaScript, lo que puede modificar el HTML que se muestra. En una solicitud fetch, solo obtienes el HTML sin procesar, sin modificaciones de JavaScript.

Solo con fines de prueba, hagamos una solicitud fetch a nuestro sitio web de destino y escribamos el HTML resultante en un archivo local:

//index.js

const fs = require('fs');

(async () => {

    const response =  await fetch('https://chartmasters.org/best-selling-artists-of-all-time/');

    const raw_html = await response.text();

    fs.writeFileSync('raw-best-selling-artists-of-all-time.html', raw_html);

})();

// it will write the raw html to raw-best-selling-artists-of-all-time.html

// try it with other websites: https://randomwordgenerator.com/

Puedes ejecutarlo con:

node index.js

Y obtendrás:

La estructura de la tabla sigue siendo la misma. Esto significa que los selectores que encontramos en el capítulo anterior siguen siendo válidos.

Bien, ahora continuemos con el código propiamente dicho:

Después de realizar la solicitud de recuperación a https://chartmasters.org/best-selling-artists-of-all-time/, tendrás que cargar el HTML sin procesar en cheerio:

const cheerio = require('cheerio');

(async () => {

    const response =  await fetch('https://chartmasters.org/best-selling-artists-of-all-time/');

    const raw_html = await response.text();

    const $ = cheerio.load(raw_html);

})();

Con cheerio cargado, veamos cómo podemos extraer los encabezados:

    const headers = $("[role=columnheader]")

    const header_names = []

    headers.each((index, el) => {

        header_names.push($(el).text())

    })
 //header_names

    [

        '#',

        'PIC',

        'Artist',

        'Total CSPC',

        'Studio Albums Sales',

        'Other LPs Sales',

        'Physical Singles Sales',

        'Digital Singles Sales',

        'Sales Update',

        'Streams EAS (Update)'

    ]

Y la primera fila:

    const first_row = $("tbody [role=row]")[0]

    const first_row_cells = $(first_row).find('[role=cell]')

    const first_row_data = []

    first_row_cells.each((index, f_r_c) => {

        const image = $(f_r_c).find('img').attr('src')

        if(image) {

            first_row_data.push(image)

        }

        else {

            first_row_data.push($(f_r_c).text())

        }

    })
   //first_row_data

     [

        '1',

        'https://i.scdn.co/image/ab6761610000f178e9348cc01ff5d55971b22433',

        'The Beatles',

        '421,300,000',

        '160,650,000',

        '203,392,000',

        '116,080,000',

        '35,230,000',

        '03/01/17',

        '17,150,000 (01/03/23)'

      ]

¿Recuerdas cuando extraímos la tabla HTML con JavaScript en la consola de Herramientas de desarrollo del navegador? En este punto, hemos replicado la misma funcionalidad que implementamos allí, pero en el contexto del proyecto Node.js. Puedes repasar el último capítulo y observar las numerosas similitudes entre ambas implementaciones.

Continuando, reescribamos el código para extraer todas las filas:

    const rows = $("tbody [role=row]")

    const rows_data = []

    rows.each((index, row) => {

        const row_cell_data = []

        const cells = $(row).find('[role=cell]')

        cells.each((index, cell) => {

            const image = $(cell).find('img').attr('src')

            if(image) {

                row_cell_data.push(image)

            }

            else {

                row_cell_data.push($(cell).text())

            }

        })
        rows_data.push(row_cell_data)

    })

    //rows_data

    [

        [

          '1',

          'https://i.scdn.co/image/ab6761610000f178e9348cc01ff5d55971b22433',

          'The Beatles',

          '421,300,000',

          '160,650,000',

          '203,392,000',

          '116,080,000',

          '35,230,000',

          '03/01/17',

          '17,150,000 (01/03/23)'

        ],

        [

          '2',

          'https://i.scdn.co/image/ab6761610000f178a2a0b9e3448c1e702de9dc90',

          'Michael Jackson',

          '336,084,000',

          '182,600,000',

          '101,997,000',

          '79,350,000',

          '79,930,000',

          '09/27/17',

          '15,692,000 (01/06/23)'

        ],

        ...

    ]

Ahora que hemos obtenido los datos, veamos cómo podemos exportarlos.

Exportación de los datos

Una vez que hayas obtenido con éxito los datos que deseas extraer, es importante considerar cómo quieres almacenar la información. Las opciones más populares son .json y .csv. Elige el formato que mejor se adapte a tus necesidades y requisitos específicos.

Exportación de los datos a json

Si quieres exportar los datos a .json, primero debes agrupar los datos en un objeto JavaScript que se asemeje al formato .json.

Tenemos una matriz de nombres de encabezados (header_names) y otra matriz (rows_data, una matriz de matrices) que contiene los datos de las filas. El formato .json almacena la información en pares clave-valor. Necesitamos agrupar nuestros datos de tal manera que sigan esa regla:

[ // this is what we need to obtain

  {

    '#': '1',

    PIC: 'https://i.scdn.co/image/ab6761610000f178e9348cc01ff5d55971b22433',

    Artist: 'The Beatles',

    'Total CSPC': '421,300,000',

    'Studio Albums Sales': '160,650,000',

    'Other LPs Sales': '203,392,000',

    'Physical Singles Sales': '116,080,000',

    'Digital Singles Sales': '35,230,000',

    'Sales Update': '03/01/17',

    'Streams EAS (Update)': '17,150,000 (01/03/23)'

  },

  {

    '#': '2',

    PIC: 'https://i.scdn.co/image/ab6761610000f178a2a0b9e3448c1e702de9dc90',

    Artist: 'Michael Jackson',

    'Total CSPC': '336,084,000',

    'Studio Albums Sales': '182,600,000',

    'Other LPs Sales': '101,997,000',

    'Physical Singles Sales': '79,350,000',

    'Digital Singles Sales': '79,930,000',

    'Sales Update': '09/27/17',

    'Streams EAS (Update)': '15,692,000 (01/06/23)'

  } 

  ...

]

Así es como puedes lograrlo:

     // go through each row

 const table_data = rows_data.map(row => {

        // create a new object

        const obj = {};

        // forEach element in header_names

        header_names.forEach((header_name, i) => {

          // add a key-value pair to the object where the key is the current header name and the value is the value at the same index in the row

          obj[header_name] = row[i];

        });

        // return the object

        return obj;

 });

Ahora puedes utilizar la función JSON.stringify() para convertir el objeto JavaScript en una cadena .json y, a continuación, escribirla en un archivo.


 const fs = require('fs');

 const table_data_json_string = JSON.stringify(table_data, null, 2)

 fs.writeFile('table_data.json', table_data_json_string, (err) => {

if (err) throw err;

console.log('The file has been saved as table_data.json!');

 })

Exportar los datos a CSV

El formato .csv significa «valores separados por comas». Si quieres guardar tu tabla en formato .csv, tendrás que escribirla en un formato similar a este:

id,name,age // the table headers followed by the rows

1,Alice,20

2,Bob,25

3,Charlie,30

Los datos de nuestra tabla consisten en una matriz de nombres de encabezados (header_names) y otra matriz (rows_data, una matriz de matrices) que contiene los datos de las filas. Así es como puedes escribir estos datos en un archivo .csv:

    let csv_string = header_names.join(',') + '\n'; // add the headers

    // forEach row in rows_data

    rows_data.forEach(row => {

      // add the row to the CSV string

      csv_string += row.join(',') + '\n';

    });

   

    // write the string to a file

    fs.writeFile('table_data.csv', csv_string, (err) => {

      if (err) throw err;

      console.log('The file has been saved as table_data.csv!');

    });

Evita que te bloqueen

¿Alguna vez te has encontrado con el problema de intentar extraer datos de un sitio web y darte cuenta de que la página de la que intentas extraer información no se carga por completo? Esto puede resultar frustrante, especialmente si sabes que el sitio web utiliza JavaScript para generar su contenido. No tenemos la capacidad de ejecutar JavaScript como lo hace un navegador normal, lo que puede dar lugar a datos incompletos o incluso a que te bloqueen el acceso al sitio web por realizar demasiadas solicitudes en un breve periodo de tiempo.

Una solución a este problema es WebScrapingApi. Con nuestro servicio, solo tienes que realizar solicitudes a nuestra API y esta se encargará de todas las tareas complejas por ti. Ejecutará JavaScript, rotará proxies e incluso gestionará los CAPTCHAs.

A continuación te mostramos cómo puedes realizar una sencilla solicitud de recuperación a una <target_url> y escribir la respuesta en un archivo:

const fs = require('fs');

(async () => {

    const result = await fetch('https://api.webscrapingapi.com/v1?' + new URLSearchParams({

        api_key: '<api_key>',

        url: '<target_url>',

        render_js: 1,

        proxy_type: 'residential',

    }))

   

    const html = await result.text();

    fs.writeFileSync('wsa_test.html', html);

})();

Puedes obtener una API_KEY gratuita creando una nueva cuenta en https://www.webscrapingapi.com/

Al especificar el parámetro render_js=1, habilitarás la capacidad de WebScrapingAPI para acceder a la página web de destino utilizando un navegador sin interfaz gráfica, lo que permite que los elementos JavaScript de la página se carguen antes de enviarte el resultado final del scraping.

Echa un vistazo a https://docs.webscrapingapi.com/webscrapingapi/advanced-api-features/proxies para descubrir las capacidades de nuestros proxies rotativos.

Conclusión

En este artículo, hemos aprendido sobre el potencial del web scraping de tablas HTML con JavaScript y cómo puede ayudarnos a extraer datos valiosos de sitios web. Hemos explorado la estructura de las tablas HTML y hemos aprendido a utilizar la biblioteca cheerio en combinación con Node.js para extraer datos de ellas fácilmente. También hemos visto diferentes formas de exportar los datos, incluyendo los formatos CSV y JSON. Siguiendo los pasos descritos en este artículo, ahora deberías tener una base sólida para extraer datos de tablas HTML en cualquier sitio web.

Tanto si eres un profesional experimentado como si acabas de empezar con tu primer proyecto de scraping, WebScrapingAPI está aquí para ayudarte en cada paso del camino. Nuestro equipo estará encantado de responder a cualquier pregunta que puedas tener y ofrecerte orientación sobre tus proyectos. Así que, si alguna vez te sientes atascado o simplemente necesitas una mano amiga, no dudes en ponerte en contacto con nosotros.

Acerca del autor
Mihai Maxim, Desarrollador Full Stack @ WebScrapingAPI
Mihai MaximDesarrollador Full Stack

Mihai Maxim es desarrollador full stack en WebScrapingAPI, donde colabora en todas las áreas del producto y ayuda a crear herramientas y funciones fiables para la plataforma.

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.