⟳ Automazione

Unire decine di file Excel in uno solo con Python e pandas

Come consolidare molti file Excel o CSV in un'unica tabella con pandas: leggere una cartella, allineare colonne, tracciare l'origine, trovare duplicati.

Ogni filiale manda il proprio file di vendite, ogni tecnico compila il proprio foglio ore, ogni mese il gestionale esporta un file nuovo. A fine trimestre qualcuno deve aprirli uno per uno e copiare tutto in un unico foglio. È un lavoro lungo e soggetto a errori: una riga saltata, un file dimenticato, una colonna incollata nel posto sbagliato. La libreria pandas permette di fare il consolidamento in pochi secondi e, soprattutto, nello stesso modo ogni volta.

L'idea di base

pandas rappresenta una tabella come un DataFrame. Il consolidamento consiste in tre passi: leggere ogni file in un DataFrame, metterli in una lista, concatenarli con pd.concat.

pip install pandas openpyxl
from pathlib import Path
import pandas as pd

cartella = Path("C:/Dati/Vendite filiali")
tabelle = []
for file in sorted(cartella.glob("*.xlsx")):
    df = pd.read_excel(file)
    df["file_origine"] = file.name
    tabelle.append(df)

totale = pd.concat(tabelle, ignore_index=True)
totale.to_excel("vendite_consolidate.xlsx", index=False)
print(len(tabelle), "file,", len(totale), "righe")

ignore_index=True rinumera le righe da capo, evitando indici duplicati. Il pacchetto openpyxl è necessario perché pandas lo usa per leggere e scrivere i file .xlsx.

Sapere sempre da dove arriva ogni riga

La colonna file_origine aggiunta nell'esempio è il dettaglio più utile di tutto lo script. Quando una cifra nel consolidato sembra sbagliata, permette di risalire subito al file che l'ha prodotta. Se il nome del file contiene informazioni, come vendite_Torino_2025-03.xlsx, si possono anche estrarre in colonne separate:

filiale, periodo = file.stem.split("_")[1:3]
df["filiale"] = filiale
df["periodo"] = periodo

Questo funziona solo se i nomi seguono una convenzione rigorosa, ed è un buon motivo per concordarla con chi invia i file.

Quando le colonne non coincidono

Nella realtà i file non sono mai perfettamente uguali. Qualcuno scrive «Importo», qualcun altro «Importo €», un terzo aggiunge una colonna di note. pd.concat allinea le colonne per nome: quelle con nomi diversi diventano colonne separate, piene di valori vuoti per i file che non le hanno. Il rimedio è normalizzare i nomi prima di concatenare:

rinomina = {"importo €": "importo", "imp.": "importo", "data doc": "data"}

df.columns = df.columns.str.strip().str.lower()
df = df.rename(columns=rinomina)
df = df[["data", "cliente", "importo"]]

L'ultima riga tiene solo le colonne attese, nell'ordine voluto. Se una manca, pandas solleva un errore che indica quale: meglio un errore chiaro che un consolidato incompleto.

Intestazioni non in prima riga e fogli multipli

Molti file hanno qualche riga di titolo prima della tabella vera. Il parametro skiprows le salta: pd.read_excel(file, skiprows=3) inizia a leggere dalla quarta riga. Se il dato si trova in un foglio specifico, si indica con sheet_name="Vendite". Con sheet_name=None si ottengono invece tutti i fogli del file sotto forma di dizionario, utile quando ogni foglio rappresenta un mese.

Anche i CSV

Lo stesso schema vale per i CSV, con qualche attenzione in più sul formato italiano:

df = pd.read_csv(file, sep=";", decimal=",", thousands=".", encoding="utf-8")

Senza decimal="," l'importo 1.234,56 verrebbe letto come testo. Se il file proviene da un vecchio gestionale e le lettere accentate appaiono come simboli strani, provate encoding="cp1252", la codifica storica di Windows.

Duplicati e controlli

Capita che lo stesso file venga inviato due volte con nomi diversi, o che due esportazioni si sovrappongano di qualche giorno. Prima di consegnare il consolidato conviene cercare i duplicati:

doppi = totale.duplicated(subset=["data", "cliente", "importo"], keep=False)
print(doppi.sum(), "righe sospette")
totale[doppi].to_excel("da_verificare.xlsx", index=False)

Non conviene eliminarli automaticamente alla cieca: due vendite identiche nello stesso giorno possono essere reali. Salvarle in un file a parte permette a una persona di decidere. Nel mio lavoro aggiungo anche un riepilogo per file, con numero di righe e somma degli importi, da confrontare con i totali che ogni mittente dichiara.

riepilogo = totale.groupby("file_origine")["importo"].agg(["count", "sum"])
print(riepilogo)
Problema Soluzione in pandas
Nomi di colonna diversi str.lower(), rename()
Righe di titolo skiprows
Foglio specifico sheet_name
Numeri in formato italiano decimal=",", thousands="."
Duplicati duplicated()
Verifica per file groupby().agg()

In sintesi

  • pd.concat unisce in un colpo i DataFrame letti da tutti i file di una cartella.
  • Aggiungete sempre una colonna con il nome del file di origine.
  • Normalizzate i nomi delle colonne e selezionate solo quelle attese.
  • Per i CSV italiani indicate separatore, decimali e codifica.
  • Segnalate i duplicati invece di eliminarli e confrontate i totali per file.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica, unisce il rigore dell'analisi tecnica all'attenzione per le persone che usano la tecnologia.

Leggi anche