Cómo raspar una tabla HTML en JavaScript
Mihai Maxim el 31 Ene 2023

Saber cómo raspar tablas HTML con javascript puede ser una habilidad crucial cuando se trata de datos tabulares que aparecen en la web. Los sitios web suelen mostrar información importante, como detalles de productos, precios, niveles de inventario y datos financieros en tablas. Poder extraer esta información es 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 construiremos un sencillo pero potente programa para extraer datos de ellas y exportarlos a un archivo CSV o JSON. Utilizaremos Node.js y cheerio para que el proceso sea pan comido.
Comprender la estructura de una tabla HTML
HTML tables are a powerful tool for marking up structured tabular data and displaying it in a way that is easy for users to read and understand. Tables are made up of data organized into rows and columns, and HTML provides several different elements for defining and structuring this data. A table must include at least the following elements: <table>, <tr> (table row), and <td> (table data). For added structure and semantic value, tables may also include the <th> (table header) element, as well as the <thead>, <tbody>, and <tfoot> elements.
Exploremos las etiquetas con la ayuda de un pequeño ejemplo.

Observe que la segunda tabla utiliza una sintaxis más específica

The <thead> tag will apply a bold font to the "Fruit" and "Color" cells in the second table. Other than that, you can see how both syntaxes achieve the same organization of the data.
Al extraer tablas de la web, es importante tener en cuenta que puede encontrarse 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.
Scraping de tablas HTML con Node.js y cheerio
¡Bienvenido a la parte divertida! Hemos aprendido sobre la estructura y el propósito de las tablas HTML, y ahora es el momento de poner ese conocimiento en acción haciendo algo 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 configurando nuestro entorno de trabajo e instalando las librerías necesarias. A continuación, exploraremos nuestro sitio web de destino e idearemos 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.
Establecer el entorno de trabajo
Muy bien, ¡empecemos con nuestro nuevo proyecto! Antes de empezar, asegúrate de que tienes node.js instalado. Puedes descargarlo de https://nodejs.org/en/.
Ahora abre tu editor de código favorito, abre el directorio de tu proyecto y ejecuta (en el terminal):
npm init -y
Esto inicializará un nuevo proyecto y creará un archivo package.json por defecto.
{
"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 usando la sentencia "import", añade esto a tu archivo package.json:
"tipo": "module",
// esto te permitirá usar la sentencia import
// ej: 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.
Vamos a utilizar 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 está establecido. En el próximo capítulo exploraremos la estructura de la tabla de los artistas más vendidos de todos los tiempos.
Prueba del sitio de destino con DevTools

Inspeccionando la pestaña "Elementos" de las Herramientas de desarrollo, podemos extraer información valiosa sobre la estructura de la tabla:
The table is stored in a <thead>, <tbody> format.
A todos los elementos de la pestaña 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 herramientas de desarrollo para probar algunos selectores.
Extraigamos los nombres de las cabeceras utilizando el atributo role="columnheader

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

Como puede ver:
Podemos utilizar "[role=columheader]" para seleccionar todos los elementos de cabecera.
Podemos utilizar "tbody [role=row]" para seleccionar todos los elementos de la fila.
Para cada fila, podemos utilizar "[role=cell]" para seleccionar sus celdas.
Una cosa a tener en cuenta es que la celda PIC contiene una imagen y debemos escribir una regla especial para extraer su URL.
Implementación de un raspador de tablas HTML
Ahora es el momento de hacer las cosas un poco más avanzadas mediante el uso de Node.js y cheerio.
Para obtener el HTML de un sitio web en un proyecto Node.js, tendrás que hacer una petición 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 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 usar selectores CSS conocidos para extraer datos del HTML, tal como lo harías en un navegador.
También es importante tener en cuenta que el HTML devuelto por una solicitud de obtención puede ser diferente del HTML que se ve en el navegador. Esto se debe a que el navegador ejecuta JavaScript, que puede modificar el HTML que se muestra. En una solicitud de obtención, sólo se obtiene el HTML sin procesar, sin ninguna modificación de JavaScript.
A modo de prueba, vamos a realizar una solicitud de búsqueda a nuestro sitio web de destino y escribir 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 lo conseguirás:

La estructura de la tabla sigue siendo la misma. Esto significa que los selectores que encontramos en el capítulo anterior siguen siendo relevantes.
Bien, ahora continuemos con el código real:
Después de hacer la solicitud de obtención a https://chartmasters.org/best-selling-artists-of-all-time/, tendrá 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 las cabeceras:
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 hicimos scraping de la tabla HTML con JavaScript en la consola de Browser Developer Tools? En este punto, replicamos la misma funcionalidad que implementamos allí, pero en el contexto del proyecto Node.js. Puedes revisar el último capítulo y observar las muchas similitudes entre ambas implementaciones.
A continuación, vamos a reescribir el código para raspar 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.
Exportar los datos
Una vez que haya obtenido los datos que desea raspar, es importante considerar cómo desea 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.
Exportar los datos a json
Si desea exportar los datos a .json, primero debe agrupar los datos en un objeto JavaScript que se asemeje al formato .json.
Tenemos un array de nombres de cabecera (header_names) y otro array (rows_data, un array de arrays) que contiene los datos de las filas. El formato .json almacena la información en pares clave-valor. Necesitamos empaquetar nuestros datos de forma 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)'
}
...
]
He aquí cómo conseguirlo:
// 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 puede utilizar la función JSON.stringify() para convertir el objeto JavaScript en una cadena .json y luego 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 .csv, tendrás que escribirla en un formato similar a este:
id,name,age // las cabeceras de la tabla seguidas de las filas
1,Alice,20
2,Bob,25
3,Charlie,30
Los datos de nuestra tabla consisten en un array de nombres de cabecera (header_names) y otro array (rows_data, un array de arrays) que contiene los datos de las filas. He aquí cómo 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!');
});
Evitar el bloqueo
¿Alguna vez te has encontrado con el problema de intentar hacer scraping de un sitio web y darte cuenta de que la página de la que estás intentando extraer información no se está cargando completamente? Esto puede ser 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 se nos prohíba el acceso al sitio web por realizar demasiadas solicitudes en un corto período de tiempo.
Una solución a este problema es WebScrapingApi. Con nuestro servicio, puede simplemente hacer peticiones a nuestra API y ésta se encargará de todas las tareas complejas por usted. Ejecutará JavaScript, rotará proxies e incluso manejará CAPTCHAs.
Here is how you can make a simple fetch request to a <target_url> and write the response to a file:
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);
})();
Puede obtener una API_KEY gratuita creando una nueva cuenta en https://www.webscrapingapi.com/.
Al especificar el parámetro render_js=1, habilitará la capacidad de WebScrapingAPI de acceder a la página web de destino utilizando un navegador sin cabeza que permite que los elementos de página JavaScript se rendericen antes de devolverle el resultado final del raspado.
Visite https://docs.webscrapingapi.com/webscrapingapi/advanced-api-features/proxies para descubrir las capacidades de nuestros proxies rotatorios.
Conclusión
En este artículo, aprendimos sobre el poder del web scraping de tablas HTML con JavaScript y cómo puede ayudarnos a extraer datos valiosos de sitios web. Exploramos la estructura de las tablas HTML y aprendimos a usar la biblioteca cheerio en combinación con Node.js para extraer fácilmente datos de ellas. También vimos diferentes formas de exportar los datos, incluidos los formatos CSV y JSON. Siguiendo los pasos descritos en este artículo, ahora deberías tener una base sólida para raspar tablas HTML en cualquier sitio web.
Si usted es un profesional experimentado o acaba de empezar con su primer proyecto de scraping, WebScrapingAPI's está aquí para ayudarle en cada paso del camino. Nuestro equipo está siempre dispuesto a responder cualquier pregunta que pueda tener y ofrecerle orientación en sus proyectos. Así que si alguna vez se siente atascado o simplemente necesita una mano amiga, no dude en ponerse en contacto con nosotros.
Noticias y actualidad
Manténgase al día de las últimas guías y noticias sobre raspado web suscribiéndose a nuestro boletín.
We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Artículos relacionados

Aprenda a scrapear sitios web dinámicos con JavaScript utilizando Scrapy y Splash. Desde la instalación hasta la escritura de una araña, el manejo de la paginación y la gestión de las respuestas de Splash, esta completa guía ofrece instrucciones paso a paso tanto para principiantes como para expertos.


Descubra cómo extraer y organizar datos de forma eficaz para el raspado web y el análisis de datos mediante el análisis sintáctico de datos, las bibliotecas de análisis sintáctico HTML y los metadatos de schema.org.


Aprende a usar proxies con Axios y Node.js para un raspado web eficiente. Consejos, ejemplos de código y los beneficios de usar WebScrapingAPI incluidos.
