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.
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:
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
datetimeo un44927.0crudo 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.
openpyxlcondata_only=Falsedevuelve=SUM(A1:A10); condata_only=Truedevuelve el valor cacheado — que esNonesi 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:
| Lenguaje | API normal | API de baja memoria |
|---|---|---|
| Python (leer) | load_workbook() | load_workbook(..., read_only=True) + wb.close() |
| Python (escribir) | Workbook() | Workbook(write_only=True) |
| JavaScript | xlsx.readFile() | Sin lector streaming real — convierte por hoja con xlsx.utils.sheet_to_csv |
| Java | XSSFWorkbook | XSSFReader (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
| Lenguaje | Librería | Fortalezas | Limitaciones |
|---|---|---|---|
| Python | openpyxl | Lectura/escritura .xlsx completa: estilos, fórmulas, gráficos | Necesita modo read_only en archivos enormes |
| Python | pandas | read_excel() devuelve un DataFrame; engine="calamine" (pandas 2.2+) es mucho más rápido | Pierde el formato |
| Python | xlrd | Lee .xls legacy | Soporte .xlsx eliminado en xlrd 2.0 |
| JavaScript | SheetJS xlsx | Navegador + Node, exporta a CSV/JSON | Estilos de celda requieren la versión Pro |
| Java | Apache POI | Estándar enterprise, fórmulas y gráficos | Consumo de memoria elevado |
| Java | FastExcel | Escritura en streaming, baja memoria | Enfocado a escritura |
Mejores Prácticas
- Valida nombres de hojas antes de indexar. Los usuarios renombran hojas;
wb["Data"]sobre una hoja renombrada lanzaKeyError. Revisawb.sheetnameso 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 modoread_onlyliberan handles que de otra forma se acumulan en jobs de importación largos. - Prefiere
.xlsxsobre.xls. El formato XML permite ~1M de filas por hoja (vs 65k) y tiene mucho mejor soporte de librerías.
Errores Comunes
- Usar
xlrdsobre.xlsx. xlrd 2.0 eliminó el formato por completo; para.xlsantiguos usaxlrd<2.0opython-calamine. - Esperar que
data_only=Truedevuelva 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_rowscon 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.valuepuede serstr,float,datetimeoNonesegún el formato; revisacell.data_typeen 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:
.xlsxes 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()exponefile_sizepor 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
.xlsmpueden embeber VBA. Leerlos es seguro —keep_vba=Truede openpyxl preserva pero nunca ejecuta macros — simplemente no reenvíes archivos con macros a usuarios sin motivo.
Ver También
- Documentación de openpyxl — la API Python completa para libros, estilos y gráficos.
- Docs de SheetJS
xlsx— la librería JavaScript usada arriba. - Apache POI — los componentes Java para Excel (
XSSFWorkbook,XSSFReader). - Leer y Escribir Excel en Python — la versión más profunda con pandas/openpyxl de esta tarea.
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.
Recursos Relacionados
Leer y Escribir Excel en Python (openpyxl + pandas)
Cómo leer, escribir y formatear hojas de cálculo Excel en Python con pandas y openpyxl, con ejemplos listos para copiar.
RecipeImportar Datos desde CSV/Excel
Cómo parsear e importar datos desde archivos CSV y Excel con validación, streaming e inserción por lotes.
RecipeExportar Datos a CSV y Excel
Cómo exportar datos estructurados a archivos CSV y Excel de forma eficiente.
RecipeAnalizar Archivos CSV
Cómo analizar archivos CSV en Python, Java y JavaScript con ejemplos de código prácticos.
RecipeExtraer Texto de PDFs en Python, JavaScript y Java
Extrae texto, tablas y metadatos de archivos PDF con Python, JavaScript y Java, incluidos archivos cifrados y documentos escaneados con OCR.
RecipeConvertir JSON a CSV
Cómo convertir datos JSON a formato CSV en Python, Java y JavaScript: aplana objetos anidados, desenrolla arrays y genera salida lista para Excel.