Estoy haciendo un proyecto web con titiritero .
En una de las páginas del sitio web que estoy ejecutando (no me pertenece), de 12 tablas , hay una tabla html dentro de una tabla, que dentro de tbody y tr , hay dos elementos td . Sin clases y sin identificaciones.
El primer td es siempre la columna y el segundo es el valor .
¿Cómo puedo convertir esta tabla específica en una línea en una hoja de cálculo de Excel o un .csv con JavaScript y Puppeteer ?
La respuesta de Dave a continuación solo funciona si tiene el html de la página y si el contenido. funciona, lo que no funciona para mí, incluso en un ejemplo.
Aquí está la tabla que estoy tratando de convertir. El real tiene 29 columnas.
<table style="color:Black;background-color:LightGrey;height:400px;width:898px;border: 1px solid grey"> <tbody> <tr> <td> <table> <tbody> <tr> <td>Column1</td> <td>Value1</td> </tr> <tr> <td>Column2</td> <td>Value2</td> </tr> <tr> <td>Column3</td> <td>Value3</td> </tr> </tbody> </table> </td> </tr> </tbody> </table>La salida .csv debe ser:
Column1,Column2,Column3 Value1,Value2,Value3Esta solución ha sido probada en su página HTML de muestra. Deberá diseñar el selector de CSS para que sea lo suficientemente específico en la página real. Y/o filtre el elementHandles resultante:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://renatocfrancisco.github.io/getTableWithPuppeteer/'); // Get array of elementHandles from page matching this CSS selector. const elements = await page.$$('table table td'); const columns = []; const values = []; // Process the elementHandles. let i = 0; for (const element of elements) { // Extract text from elementHandle. const text = await element.evaluate(el => el.textContent); if ((i++ % 2) == 0) { // Even elements are columns. columns.push(text); } else { // Odd elements are values. values.push(text); } }; // Construct CSV string. console.log(`${columns.join(',')}\n${values.join(',')}`); await browser.close(); })();Producción:
$ nodo ./src/index.js columna1,columna2,columna3 valor1,valor2,valor3
actualizar:
Esta es una variación que no usa Titiritero; solo busque y Cheerio.js . Es mucho más rápido y usa menos recursos, por lo que recomiendo usar esta versión cuando sea posible. (Su URL de muestra se puede procesar correctamente sin Titiritero).
const cheerio = require('cheerio'); (async () => { const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const response = await fetch('https://renatocfrancisco.github.io/getTableWithPuppeteer/'); const html = await response.text(); const $ = cheerio.load(html); // Get array of elements from page matching this CSS selector. const elements = $('table table td'); const columns = []; const values = []; // Process the elementHandles. let i = 0; for (const element of elements) { // Extract text from elementHandle. const text = $(element).text(); if ((i++ % 2) == 0) { // Even elements are columns. columns.push(text); } else { // Odd elements are values. values.push(text); } }; // Construct CSV string. console.log(`${columns.join(',')}\n${values.join(',')}`); })();Producción:
$ nodo ./src/index.js columna1,columna2,columna3 valor1,valor2,valor3
Esto es un poco engorroso ya que he desglosado los pasos para ilustrar lo que estamos haciendo. Podría simplificarse mucho si el tbody relevante tuviera una ID para que pudiéramos hacer una referencia directa a él usando getElementById , pero en su lugar tenemos que navegar por el árbol DOM (la tabla relevante está dentro de una celda de una tabla externa).
Habiendo hecho una referencia a una colección de filas de tablas relevantes, podemos recorrerlas para extraer los datos necesarios. Los bucles crean una cadena separada por comas para cada fila (de salida), almacenándolas en una matriz. La matriz luego se une en líneas para dar salida csv.
Sin duda, esto podría simplificarse, pero funciona. Retazo:
const innerTable = document.getElementsByTagName('table')[1]; const tableBody = innerTable.getElementsByTagName('tbody')[0]; const tableRows = tableBody.children; let csv = []; for (let row=0; row<tableRows.length; row++) { const cells = tableRows[row].children; for (let cell=0; cell<cells.length; cell++) { if (csv[cell]) {csv[cell] += `,${cells[cell].innerText}`;} else {csv[cell] = `${cells[cell].innerText}`;} } // next cell; } // next row; csvString = csv.join("\n"); console.log(csvString); <table style="color:Black;background-color:LightGrey;height:400px;width:898px;border: 1px solid grey"> <tbody> <tr> <td> <table> <tbody> <tr> <td>Column1</td> <td>Value1</td> </tr> <tr> <td>Column2</td> <td>Value2</td> </tr> <tr> <td>Column3</td> <td>Value3</td> </tr> </tbody> </table> </td> </tr> </tbody> </table>