Ú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:
pandasyopenpyxl
Instala en Windows/Mac/Linux: post que te guía paso a paso
pip install pandas openpyxlTip 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
.xlsxde una carpeta - Toma una hoja (por nombre o índice)
- Agrega columna
_archivo_origenpara 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_excely mete tus.xlsx. - Ajusta
HOJAsi 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_namecorrecto. - Llave no coincide → normaliza tipo
strystrip(). - Duplicados inesperados → revisa
validate="m:1"o1:1enmergepara 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)


