Leer y escribir Excel con Python usando openpyxl
Cómo abrir un archivo .xlsx, recorrer sus filas, modificar celdas y generar un reporte nuevo desde Python. Con los detalles que rompen los scripts la primera vez.
Tienes un Excel con cientos de filas y necesitas extraer datos, recalcular algo o generar un reporte. Hacerlo a mano es una tarde; con Python son unas pocas líneas y se repite cuantas veces quieras.
La librería es openpyxl, que trabaja con archivos .xlsx (el formato moderno de Excel).
pip install openpyxl
Un aviso desde ya: openpyxl no lee archivos .xls antiguos. Si tu archivo es .xls, ábrelo en Excel y guárdalo como .xlsx, o usa otra librería. Es la primera piedra con la que tropieza casi todo el mundo.
Leer un archivo
from openpyxl import load_workbook
wb = load_workbook("ventas.xlsx")
hoja = wb.active # la hoja activa
# Una celda concreta
print(hoja["A1"].value)
print(hoja.cell(row=1, column=1).value) # equivalente
Fíjate en el .value al final. Sin él no obtienes el contenido sino el objeto celda, y ahí es donde a mucha gente le sale un <Cell 'Hoja1'.A1> en lugar del dato. Es el error más común al empezar.
Para elegir una hoja específica en vez de la activa:
hoja = wb["Enero"] # por nombre
print(wb.sheetnames) # ver todas las hojas
Recorrer las filas
for fila in hoja.iter_rows(min_row=2, values_only=True):
producto, cantidad, precio = fila
print(f"{producto}: {cantidad} x {precio}")
Dos detalles que ahorran problemas. El min_row=2 salta la fila de encabezados, que casi nunca quieres procesar como dato. Y values_only=True te entrega directamente los valores en lugar de objetos celda, así puedes desempaquetarlos en variables como en el ejemplo.
Si el archivo tiene filas vacías al final (Excel a veces las arrastra), conviene filtrarlas:
for fila in hoja.iter_rows(min_row=2, values_only=True):
if fila[0] is None: # sin producto, fila vacía
continue
producto, cantidad, precio = fila
Escribir y guardar
from openpyxl import load_workbook
wb = load_workbook("ventas.xlsx")
hoja = wb.active
# Añadir una columna de total
hoja["D1"] = "Total"
for i, fila in enumerate(hoja.iter_rows(min_row=2, values_only=True), start=2):
cantidad, precio = fila[1], fila[2]
if cantidad is not None and precio is not None:
hoja.cell(row=i, column=4, value=cantidad * precio)
wb.save("ventas_con_total.xlsx")
Guarda siempre en un archivo nuevo, no sobre el original. Si algo salió mal en el script, todavía tienes los datos intactos. Es una costumbre que te salva más de una vez.
Y ojo: si el archivo está abierto en Excel mientras corres el script, el guardado falla con un error de permisos. Cierra Excel antes de ejecutar.
Crear un Excel desde cero
from openpyxl import Workbook
wb = Workbook()
hoja = wb.active
hoja.title = "Reporte"
hoja.append(["Producto", "Unidades", "Ingreso"])
hoja.append(["Teclado", 12, 480])
hoja.append(["Monitor", 5, 1250])
wb.save("reporte.xlsx")
append añade una fila completa al final, que es la forma más cómoda de volcar datos.
Un detalle sobre las fórmulas
Si tu Excel tiene celdas con fórmulas, openpyxl te devuelve la fórmula como texto ("=B2*C2"), no el resultado calculado. Para obtener los valores ya calculados:
wb = load_workbook("ventas.xlsx", data_only=True)
Con data_only=True lees el último resultado que Excel guardó. La contrapartida: si el archivo nunca se abrió en Excel tras crear la fórmula, ese valor será None, porque openpyxl no calcula fórmulas, solo lee lo que Excel dejó escrito.
Con esto cubres el 90% de lo que se necesita para automatizar Excel: leer, recorrer, calcular y generar. A partir de aquí, tareas como consolidar varios archivos en uno o generar reportes mensuales son combinaciones de estas mismas piezas.
¿Necesitas dar formato, colores o gráficos al Excel generado? Escríbeme desde contacto y lo cubrimos en un próximo artículo.