Últimamente me ha tocado trabajar con muchos reportes en Excel: descargarlos, unirlos en una sola hoja, organizarlos en diferentes pestañas o combinarlos entre sí. Hacerlo a mano suele ser tardado y, la verdad, me da un poco de flojera 😅. Por eso prefiero resolverlo con scripts sencillos en Python: rápidos, efectivos y fáciles de reutilizar. Aquí te comparto 3 casos prácticos que uso mucho y que te pueden ahorrar bastante tiempo:
- Unir muchos archivos en una sola hoja (apilar filas).
- Unir varias hojas de un mismo libro.
- Combinar por una llave (tipo VLOOKUP/BuscarV).
Requisitos
- Python 3.10+
- Librerías:
pandas
yopenpyxl
Instala en Windows/Mac/Linux: post que te guía paso a paso
pip install pandas openpyxl
Tip Windows: si pip
no funciona, prueba py -m pip install pandas openpyxl
.
Si no tienes Python, descárgalo desde python.org (marca “Add Python to PATH” al instalar).
1) Unir muchos archivos en una sola hoja
¿Cuándo usarlo?
Tienes carpetas con reportes mensuales/diarios con las mismas columnas y quieres un solo archivo consolidado.
Script: unir_archivos_en_una_hoja.py
- Lee todos los
.xlsx
de una carpeta - Toma una hoja (por nombre o índice)
- Agrega columna
_archivo_origen
para rastrear - Normaliza encabezados
# unir_archivos_en_una_hoja.py
import pandas as pd
from pathlib import Path
CARPETA = Path("data_excel") # carpeta con tus .xlsx
HOJA = "Hoja1" # o índice: 0
SALIDA = "consolidado.xlsx"
def normaliza_cols(cols):
return [str(c).strip().lower().replace(" ", "_") for c in cols]
dfs = []
for x in CARPETA.glob("*.xlsx"):
try:
df = pd.read_excel(x, sheet_name=HOJA) # o sheet_name=0
df.columns = normaliza_cols(df.columns)
df["_archivo_origen"] = x.name
dfs.append(df)
except Exception as e:
print(f"[WARN] No pude leer {x.name}: {e}")
if not dfs:
raise SystemExit("No encontré archivos .xlsx o no se pudieron leer.")
consolidado = pd.concat(dfs, ignore_index=True)
# Opcional: elimina duplicados por columnas clave
# consolidado = consolidado.drop_duplicates(subset=["folio", "fecha"])
consolidado.to_excel(SALIDA, index=False)
print(f"Listo: {SALIDA} ({len(consolidado)} filas)")
Cómo usar:
- Crea la carpeta
data_excel
y mete tus.xlsx
. - Ajusta
HOJA
si tus archivos usan otro nombre de hoja. - Corre:
python unir_archivos_en_una_hoja.py
.
2) Unir varias hojas de un mismo libro
¿Cuándo usarlo?
Tienes un solo archivo con datos repartidos en varias hojas y quieres todo en una.
Script: unir_hojas_de_un_libro.py
- Lee todas las hojas de un libro
- Apila todo en una sola tabla
- Agrega columna
_hoja_origen
# unir_hojas_de_un_libro.py
import pandas as pd
ENTRADA = "reporte_multihojas.xlsx"
SALIDA = "reporte_unico.xlsx"
xls = pd.ExcelFile(ENTRADA)
dfs = []
for hoja in xls.sheet_names:
df = pd.read_excel(xls, sheet_name=hoja)
df.columns = [str(c).strip().lower().replace(" ", "_") for c in df.columns]
df["_hoja_origen"] = hoja
dfs.append(df)
unico = pd.concat(dfs, ignore_index=True)
unico.to_excel(SALIDA, index=False)
print(f"Listo: {SALIDA} ({len(unico)} filas, {len(xls.sheet_names)} hojas)")
3) Combinar por llave (tipo VLOOKUP)
¿Cuándo usarlo?
Tienes dos tablas: por ejemplo, pagos y alumnos. Quieres unirlas por una clave (ej. matricula
).
Script: combinar_por_llave.py
- Une
left
(izquierda conserva todo) oinner
(solo coincidencias) - Normaliza tipos de datos para evitar “no coincide”
# combinar_por_llave.py
import pandas as pd
IZQ = "pagos.xlsx" # tabla base
DER = "alumnos.xlsx" # tabla a cruzar
HOJA_IZQ = 0
HOJA_DER = 0
LLAVE_IZQ = "matricula"
LLAVE_DER = "matricula"
MODO = "left" # left / inner / right / outer
SALIDA = "pagos_con_datos.xlsx"
def limpia(df):
df = df.copy()
df.columns = [str(c).strip().lower().replace(" ", "_") for c in df.columns]
return df
df_izq = limpia(pd.read_excel(IZQ, sheet_name=HOJA_IZQ))
df_der = limpia(pd.read_excel(DER, sheet_name=HOJA_DER))
# Normaliza llave a string (muy importante)
df_izq[LLAVE_IZQ] = df_izq[LLAVE_IZQ].astype(str).str.strip()
df_der[LLAVE_DER] = df_der[LLAVE_DER].astype(str).str.strip()
unido = pd.merge(
df_izq, df_der,
left_on=LLAVE_IZQ, right_on=LLAVE_DER,
how=MODO, validate="m:1" # cada pago mapea a un alumno
)
unido.to_excel(SALIDA, index=False)
print(f"Listo: {SALIDA} ({len(unido)} filas)")
Si tu llave viene con ceros a la izquierda (ej. “00123”), mantenerla como texto evita que Excel los quite.
Errores comunes y cómo evitarlos
- “Worksheet name is invalid” → revisa
sheet_name
correcto. - Llave no coincide → normaliza tipo
str
ystrip()
. - Duplicados inesperados → revisa
validate="m:1"
o1:1
enmerge
para detectar errores. - Celdas vacías → usa
fillna("")
odropna(subset=["col"])
. - Encoding raro en CSV → usa
encoding="utf-8-sig"
.
Script “todo en uno” por argumentos
Útil si quieres correrlo con parámetros sin editar el archivo.
# excel_cli.py
import argparse, sys
from pathlib import Path
import pandas as pd
def normaliza_cols(cols): return [str(c).strip().lower().replace(" ", "_") for c in cols]
def unir_archivos(carpeta, hoja, salida):
dfs=[]
for x in Path(carpeta).glob("*.xlsx"):
try:
df = pd.read_excel(x, sheet_name=hoja)
df.columns = normaliza_cols(df.columns)
df["_archivo_origen"] = x.name
dfs.append(df)
except Exception as e:
print(f"[WARN] {x.name}: {e}")
if not dfs: sys.exit("Sin data.")
pd.concat(dfs, ignore_index=True).to_excel(salida, index=False)
def unir_hojas(entrada, salida):
xls = pd.ExcelFile(entrada)
dfs=[]
for hoja in xls.sheet_names:
df = pd.read_excel(xls, sheet_name=hoja)
df.columns = normaliza_cols(df.columns)
df["_hoja_origen"] = hoja
dfs.append(df)
pd.concat(dfs, ignore_index=True).to_excel(salida, index=False)
def combinar(izq, der, hoja_izq, hoja_der, llave_izq, llave_der, how, salida):
def limpia(df):
df = df.copy(); df.columns = normaliza_cols(df.columns); return df
a = limpia(pd.read_excel(izq, sheet_name=hoja_izq))
b = limpia(pd.read_excel(der, sheet_name=hoja_der))
a[llave_izq] = a[llave_izq].astype(str).str.strip()
b[llave_der] = b[llave_der].astype(str).str.strip()
pd.merge(a,b,left_on=llave_izq,right_on=llave_der,how=how,validate="m:1").to_excel(salida, index=False)
if __name__ == "__main__":
p = argparse.ArgumentParser(description="Utilidades para unir Excel")
sub = p.add_subparsers(dest="cmd", required=True)
a = sub.add_parser("apilar", help="Unir varios archivos en una hoja")
a.add_argument("--carpeta", required=True)
a.add_argument("--hoja", default=0)
a.add_argument("--salida", default="consolidado.xlsx")
b = sub.add_parser("unir_hojas", help="Unir todas las hojas de un libro")
b.add_argument("--entrada", required=True)
b.add_argument("--salida", default="reporte_unico.xlsx")
c = sub.add_parser("combinar", help="Combinar por llave (merge)")
c.add_argument("--izq", required=True)
c.add_argument("--der", required=True)
c.add_argument("--hoja_izq", default=0)
c.add_argument("--hoja_der", default=0)
c.add_argument("--llave_izq", required=True)
c.add_argument("--llave_der", required=True)
c.add_argument("--how", default="left", choices=["left","inner","right","outer"])
c.add_argument("--salida", default="salida.xlsx")
args = p.parse_args()
if args.cmd == "apilar":
unir_archivos(args.carpeta, args.hoja, args.salida)
elif args.cmd == "unir_hojas":
unir_hojas(args.entrada, args.salida)
elif args.cmd == "combinar":
combinar(args.izq, args.der, args.hoja_izq, args.hoja_der, args.llave_izq, args.llave_der, args.how, args.salida)