StackPractices
beginner Por Mathias Paulenko

Analizar Archivos Excel en Python, JavaScript y Java

Cómo leer y escribir archivos Excel (.xlsx) en Python, JavaScript y Java con openpyxl, SheetJS y Apache POI.

Temas: data

Visión General

Tarde o temprano un usuario de negocio te entrega un archivo Excel en lugar de un CSV limpio. Analizar .xlsx programáticamente te permite automatizar la ingesta de datos, generar reportes y validar exports — y a diferencia de la mayoría de formatos, cada lenguaje importante tiene una librería madura para ello. Esta receta cubre lectura y escritura de Excel en Python (openpyxl/pandas), JavaScript (SheetJS) y Java (Apache POI). Para una guía más profunda solo-Python con pandas, consulta Leer y Escribir Excel en Python.

Cuándo Usar

  • Importas datos que usuarios de negocio entregan en Excel en lugar de CSV
  • Generas reportes formateados con múltiples hojas, estilos o fórmulas
  • Validas exports de datos contra una base de datos fuente-de-verdad
  • Conviertes flujos de trabajo legacy basados en Excel en pipelines automatizados

Sáltalo cuando la fuente ya es una base de datos (consúltala directamente en lugar de pasar por Excel) o cuando el archivo en realidad es CSV — los formatos planos se analizan mucho más rápido; consulta Analizar Archivos CSV.

Cómo elegir la librería correcta:

flowchart diagram: Archivo Excel

Solución

Los fragmentos siguientes son listos para copiar. Versiones ejecutables para los tres lenguajes están en el repositorio complementario.

Python

openpyxl es el estándar para archivos .xlsx modernos. pandas lo usa como motor detrás de read_excel, así que instalar ambos cubre análisis y trabajo a nivel de celda.

pip install openpyxl pandas
from openpyxl import load_workbook

wb = load_workbook("data.xlsx")
ws = wb.active

for row in ws.iter_rows(min_row=2, values_only=True):
    print(row)
# Escritura
from openpyxl import Workbook

wb = Workbook()
ws = wb.active
ws.title = "Ventas"
ws.append(["Producto", "Cantidad", "Precio"])
ws.append(["Widget", 100, 19.99])
wb.save("output.xlsx")

JavaScript

SheetJS (el paquete xlsx) es la librería Excel más común para Node.js y el navegador.

npm install xlsx
import xlsx from "xlsx";

const workbook = xlsx.readFile("data.xlsx");
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const data = xlsx.utils.sheet_to_json(sheet);
console.log(data);
// Escritura
import xlsx from "xlsx";

const ws = xlsx.utils.aoa_to_sheet([["Nombre", "Edad"], ["Alice", 30]]);
const wb = xlsx.utils.book_new();
xlsx.utils.book_append_sheet(wb, ws, "Personas");
xlsx.writeFile(wb, "output.xlsx");

Java

Apache POI es el estándar enterprise para Excel en la JVM.

<!-- Maven -->
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>5.3.0</version>
</dependency>
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;

public class ExcelParser {
    public static void main(String[] args) throws Exception {
        try (Workbook wb = new XSSFWorkbook(new FileInputStream("data.xlsx"))) {
            Sheet sheet = wb.getSheetAt(0);
            for (Row row : sheet) {
                for (Cell cell : row) {
                    System.out.print(cell + "\t");
                }
                System.out.println();
            }
        }
    }
}

Explicación

Un archivo .xlsx es un archivo ZIP con documentos XML: workbook.xml lista las hojas, sheetN.xml contiene las celdas, y sharedStrings.xml deduplica texto para que un string almacenado una vez pueda referenciarse mil veces. Cada librería anterior es una API más amigable sobre esa estructura.

Dos detalles explican la mayoría de las sorpresas al analizar:

  • Las fechas son números. Excel almacena fechas como seriales de punto flotante (días desde 1900 o 1904 según el libro). Que obtengas un datetime o un 44927.0 crudo depende del formato numérico de la celda, así que verifica el tipo analizado antes de asumir.
  • Fórmulas vs. valores. Una celda de fórmula guarda tanto el string de la fórmula como un resultado cacheado. openpyxl con data_only=False devuelve =SUM(A1:A10); con data_only=True devuelve el valor cacheado — que es None si un script generó el archivo y Excel nunca lo abrió.

Cada librería también tiene un modo de baja memoria que entrega filas en lugar de materializar la hoja completa — la siguiente sección lo cubre.

Trabajar con Archivos Grandes

Un libro de 50MB puede consumir 500MB+ de RAM cargado sin cuidado. Las válvulas de escape por ecosistema:

LenguajeAPI normalAPI de baja memoria
Python (leer)load_workbook()load_workbook(..., read_only=True) + wb.close()
Python (escribir)Workbook()Workbook(write_only=True)
JavaScriptxlsx.readFile()Sin lector streaming real — convierte por hoja con xlsx.utils.sheet_to_csv
JavaXSSFWorkbookXSSFReader (API de eventos estilo SAX)
from openpyxl import load_workbook

# Entrega filas en streaming en lugar de cargar todo el libro
wb = load_workbook("big.xlsx", read_only=True, data_only=True)
ws = wb["Sheet1"]
for row in ws.iter_rows(values_only=True):
    process(row)
wb.close()  # obligatorio en modo read_only: libera el handle del archivo

Cuando el archivo es solo una fuente de datos que nadie abrirá en Excel, convertirlo a CSV primero suele ser la jugada pragmática — pierdes formato y fórmulas pero ganas un formato que hace streaming trivialmente. libreoffice --headless --convert-to csv big.xlsx lo hace en un paso. Si necesitas exportar datos de una app a ambos formatos, Exportar Datos a CSV y Excel cubre ese flujo.

Variantes

LenguajeLibreríaFortalezasLimitaciones
PythonopenpyxlLectura/escritura .xlsx completa: estilos, fórmulas, gráficosNecesita modo read_only en archivos enormes
Pythonpandasread_excel() devuelve un DataFrame; engine="calamine" (pandas 2.2+) es mucho más rápidoPierde el formato
PythonxlrdLee .xls legacySoporte .xlsx eliminado en xlrd 2.0
JavaScriptSheetJS xlsxNavegador + Node, exporta a CSV/JSONEstilos de celda requieren la versión Pro
JavaApache POIEstándar enterprise, fórmulas y gráficosConsumo de memoria elevado
JavaFastExcelEscritura en streaming, baja memoriaEnfocado a escritura

Mejores Prácticas

  • Valida nombres de hojas antes de indexar. Los usuarios renombran hojas; wb["Data"] sobre una hoja renombrada lanza KeyError. Revisa wb.sheetnames o accede por posición.
  • Mapea columnas por encabezado, no por índice. Construye {"Nombre": 0, "Edad": 1} desde la fila de encabezado para que una columna reordenada no corrompa silenciosamente la importación.
  • Maneja celdas combinadas explícitamente. Las librerías devuelven el valor solo en la celda superior-izquierda del rango combinado; el resto llega como None.
  • Cierra los libros. Context managers en Python, try-with-resources en Java y wb.close() en modo read_only liberan handles que de otra forma se acumulan en jobs de importación largos.
  • Prefiere .xlsx sobre .xls. El formato XML permite ~1M de filas por hoja (vs 65k) y tiene mucho mejor soporte de librerías.

Errores Comunes

  • Usar xlrd sobre .xlsx. xlrd 2.0 eliminó el formato por completo; para .xls antiguos usa xlrd<2.0 o python-calamine.
  • Esperar que data_only=True devuelva valores en archivos generados. La caché de fórmulas solo existe después de que una app de hojas de cálculo real guarde el archivo — calcula el valor en Python en su lugar.
  • Materializar hojas enormes. iter_rows con límites hace streaming; pedir todos los objetos celda por adelantado lo anula.
  • Fijar índices de columna en el código. Las columnas se reordenan constantemente en archivos reales; mapea encabezados en su lugar.
  • Asumir tipos de celda. cell.value puede ser str, float, datetime o None según el formato; revisa cell.data_type en openpyxl cuando importe.

Consideraciones de Seguridad

Los archivos Excel cruzan fronteras de confianza constantemente (uploads, adjuntos de email), y .xlsx tiene sus propias trampas:

  • Inyección de fórmulas: celdas que empiezan con =, +, - o @ se ejecutan como fórmulas cuando alguien abre el archivo en Excel. Prefija o rechaza valores controlados por el usuario que escribas en libros — la misma clase de bug que la inyección en CSV.
  • Zip bombs: .xlsx es un ZIP, así que un upload de 10MB puede descomprimirse en gigabytes de XML. Aplica límites de tamaño en uploads y verifica tamaños descomprimidos antes de extraer (zipfile.infolist() expone file_size por entrada).
  • XXE en el XML de hojas: el formato es XML hasta el fondo. Si alguna vez analizas los internos por tu cuenta en lugar de usar openpyxl/POI, usa un parser endurecido como defusedxml.
  • Macros: los archivos .xlsm pueden embeber VBA. Leerlos es seguro — keep_vba=True de openpyxl preserva pero nunca ejecuta macros — simplemente no reenvíes archivos con macros a usuarios sin motivo.

Ver También

Preguntas frecuentes

¿Debo usar pandas u openpyxl en Python?

pandas para cualquier cosa que parezca análisis (filtrar, agrupar, unir, exports masivos). openpyxl cuando controlas el archivo en sí: estilos, fórmulas, celdas combinadas, gráficos, o editar una plantilla en el lugar. pandas envuelve openpyxl para .xlsx, así que instala ambos.

¿Cómo leo archivos Excel grandes sin quedarme sin memoria?

openpyxl con read_only=True en Python, XSSFReader (la API basada en eventos) en Java, o conversión por hoja en Node. Convertir a CSV primero también funciona cuando no necesitas formato ni fórmulas.

¿Puedo preservar el formato al escribir archivos Excel?

Sí en Python (openpyxl.styles, o xlsxwriter para reportes de solo-escritura) y Java (CellStyle y Font en POI). La versión community de SheetJS solo escribe datos crudos; los estilos requieren SheetJS Pro.

¿Cómo manejo las fechas correctamente al analizar Excel?

Excel almacena fechas como números seriales. openpyxl devuelve datetime cuando el formato numérico de la celda la marca como fecha; pandas convierte columnas pasadas a parse_dates; en Java, DataFormatter renderiza el string mostrado, que luego analizas con DateTimeFormatter.

¿Cómo convierto Excel a CSV?
import pandas as pd
pd.read_excel("in.xlsx").to_csv("out.csv", index=False)

—o libreoffice --headless --convert-to csv archivo.xlsx como opción sin código. Para conversión estructurada entre formatos tabulares, consulta Convertir CSV a JSON.