Formatos y fuentes de datos 4 min de lectura

Parseo de archivos Excel: hojas, fórmulas, celdas combinadas y ejemplos en varios lenguajes

Cómo parsear archivos Excel desde código: hojas, fórmulas, celdas combinadas, formatos de fecha y ejemplos de lectura en Python, JavaScript, PHP y Go.

EW
Equipo Web-Scraping.es
Recopilación de datos para las necesidades del negocio
Publicado: 6 marzo 2025

Los archivos de Excel (.xlsx y, con menos frecuencia, el antiguo .xls) son el formato más habitual en el que las empresas envían datos: listas de precios, existencias, informes, exportaciones de los sistemas de gestión. A diferencia del CSV, un Excel no es texto plano, sino un documento estructurado: dentro de un .xlsx hay un archivo ZIP con la descripción XML de las hojas, los estilos y las fórmulas. Por eso no se puede leer «como líneas de texto»: hacen falta bibliotecas que entiendan la estructura interna del libro. El artículo continúa nuestro repaso del parseo de documentos.

Qué complica el parseo de Excel

A diferencia de un CSV plano, un libro de Excel tiene varias capas de complejidad. Primero, las hojas múltiples: los datos pueden estar repartidos entre pestañas y hay que elegir explícitamente la correcta. Segundo, las fórmulas: una celda puede almacenar tanto la fórmula =B2*C2 como su valor calculado, y lo que usted obtenga depende del modo de lectura. Tercero, las celdas combinadas, por culpa de las cuales un encabezado «cuelga» sobre varias columnas y aparecen huecos en los datos. Cuarto, los formatos: una fecha puede llegar no como 2026-06-01 sino como el número 46184 (el número de serie con que Excel guarda las fechas), y un precio, como un número con el formato de moneda almacenado aparte. Todo esto hay que tenerlo en cuenta al extraer.

Python

La herramienta básica para .xlsx es openpyxl. Da control total sobre el libro: hojas, celdas, combinaciones.

python
from openpyxl import load_workbook

wb = load_workbook("prices.xlsx", data_only=True)  # data_only=True → valores en lugar de fórmulas
ws = wb["Precios"]                                 # elegimos la hoja por su nombre

for row in ws.iter_rows(min_row=2, values_only=True):
    sku, name, price = row[0], row[1], row[2]
    print(sku, name, price)

Fíjese en data_only=True: sin él, una celda con fórmula devuelve el texto de la fórmula y no el resultado. Y recuerde que el valor calculado solo existe si el archivo se ha abierto al menos una vez en Excel — openpyxl no evalúa las fórmulas por sí mismo.

Cuando lo que se necesita no es un recorrido fila a fila sino análisis — filtros, agregados, combinación de tablas —, se recurre a pandas, que carga la hoja en un DataFrame con una sola línea (por debajo utiliza openpyxl).

python
import pandas as pd

df = pd.read_excel("prices.xlsx", sheet_name="Precios")
print(df[df["price"] > 3000])

# si hace falta, conversión a CSV
df.to_csv("prices.csv", index=False, encoding="utf-8-sig")

Para el antiguo formato binario .xls, pandas usa un motor aparte, xlrd; los archivos modernos .xlsx se procesan con openpyxl.

JavaScript / Node.js

En el ecosistema JS el estándar de facto es SheetJS (paquete xlsx). Funciona tanto en Node como en el navegador, lee casi cualquier formato de tabla y convierte cómodamente una hoja en un array de objetos.

javascript
const XLSX = require("xlsx");

const wb = XLSX.readFile("prices.xlsx");
const sheet = wb.Sheets[wb.SheetNames[0]];   // primera hoja
const rows = XLSX.utils.sheet_to_json(sheet); // array de objetos según la fila de cabecera

for (const row of rows) {
  console.log(row.sku, row.name, row.price);
}

Cuando además de leer hay que generar libros complejos con estilos, la opción adecuada es ExcelJS.

PHP

La biblioteca principal es PhpSpreadsheet (la sucesora de la antigua PHPExcel). Lee y escribe .xlsx y .xls, entiende fórmulas y formatos.

php
<?php
require "vendor/autoload.php";
use PhpOffice\PhpSpreadsheet\IOFactory;

$spreadsheet = IOFactory::load("prices.xlsx");
$rows = $spreadsheet->getActiveSheet()->toArray(null, true, true, true);

foreach (array_slice($rows, 1) as $row) { // saltamos la fila de cabecera
    echo $row["A"] . " — " . $row["B"] . " — " . $row["C"] . "\n";
}

Go

En Go el estándar de facto es excelize. Lee las hojas como filas y admite fórmulas, estilos y streaming para archivos grandes.

go
package main

import (
    "fmt"
    "github.com/xuri/excelize/v2"
)

func main() {
    f, err := excelize.OpenFile("prices.xlsx")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    rows, _ := f.GetRows("Precios")
    for _, row := range rows[1:] {
        fmt.Println(row[0], row[1], row[2])
    }
}

Consejos prácticos

Antes de escribir el parser conviene abrir el archivo y entender su estructura: dónde empiezan los datos (las primeras filas suelen estar ocupadas por la cabecera y el logotipo), si hay celdas combinadas en los encabezados, en qué hoja están los datos necesarios. Si la cabecera no es estándar, es más sencillo indicarle al parser la fila inicial que intentar adivinarla. Las fechas y los números conviene normalizarlos justo después de la lectura — llevarlos a un formato único, porque dentro de un mismo archivo a menudo aparecen escritos de maneras distintas.

Si los libros son homogéneos pero con varias hojas, celdas combinadas y fórmulas, y llegan con regularidad, configuramos un parseo automático de Excel con volcado a una base de datos o a CSV para su procesamiento posterior. Y cuando los informes no llegan en Excel sino maquetados para imprimir, eso ya es parseo de PDF — consulte el artículo correspondiente.