⟳ Automazione

Report Excel automatici con Python e openpyxl

Come creare file Excel automatici con Python e openpyxl: dati e formule, formati, larghezze, filtri, riquadri bloccati e grafici pronti da inviare.

Molti report d'ufficio nascono allo stesso modo: si esportano i dati da un gestionale, li si incolla in un file Excel, si aggiungono totali, si formatta l'intestazione, si sistemano le larghezze e si invia il file. Ogni settimana. Con la libreria openpyxl uno script Python può produrre il file finito, già formattato e pronto da inviare, senza aprire Excel e anche su un computer dove Excel non è installato.

Che cosa fa openpyxl

openpyxl legge e scrive file .xlsx lavorando direttamente sulla loro struttura interna. Non controlla Excel come farebbe una macro: crea il file come lo creerebbe Excel. Questo ha una conseguenza importante: le formule vengono scritte ma non calcolate. Il risultato apparirà quando il file verrà aperto in Excel o in un altro foglio di calcolo, che lo ricalcolerà.

pip install openpyxl

Creare il file e scrivere i dati

from openpyxl import Workbook

wb = Workbook()
ws = wb.active
ws.title = "Vendite"

ws.append(["Data", "Cliente", "Prodotto", "Quantità", "Prezzo", "Totale"])
vendite = [
    ("2025-03-03", "Rossi S.r.l.", "Licenza", 2, 120.0),
    ("2025-03-04", "Bianchi S.p.A.", "Assistenza", 5, 60.0),
]
for riga, (data, cliente, prodotto, qta, prezzo) in enumerate(vendite, start=2):
    ws.append([data, cliente, prodotto, qta, prezzo, f"=D{riga}*E{riga}"])

wb.save("vendite_settimana.xlsx")

append aggiunge una riga in fondo al foglio. La colonna Totale contiene una formula vera, non un numero calcolato in Python: chi riceve il file vede da dove nasce il valore e può modificarlo. Le formule vanno scritte con i nomi delle funzioni in inglese e la virgola come separatore degli argomenti, per esempio =SUM(F2:F50), anche se il file verrà aperto in un Excel italiano, che le mostrerà come =SOMMA(F2:F50).

Date vere, non testo

Nell'esempio le date sono stringhe: Excel le vedrà come testo e non potrà ordinarle né filtrarle per mese. Basta passare oggetti date di Python e indicare il formato di visualizzazione:

from datetime import date

ws["A2"] = date(2025, 3, 3)
ws["A2"].number_format = "DD/MM/YYYY"

Lo stesso vale per gli importi: il numero resta un numero, e il formato decide come appare.

for cella in ws["E"][1:] + ws["F"][1:]:
    cella.number_format = "#,##0.00 €"

Il codice di formato usa la convenzione inglese (virgola per le migliaia, punto per i decimali); sarà Excel a mostrarlo secondo le impostazioni locali di chi apre il file.

Formattare l'intestazione

Un report leggibile ha un'intestazione evidente. openpyxl mette a disposizione oggetti per carattere, riempimento e allineamento:

from openpyxl.styles import Font, PatternFill, Alignment

for cella in ws[1]:
    cella.font = Font(bold=True, color="FFFFFF")
    cella.fill = PatternFill("solid", fgColor="305496")
    cella.alignment = Alignment(horizontal="center")

Larghezze, filtri e riquadri bloccati

Tre ritocchi che fanno sembrare il file preparato con cura:

larghezze = {"A": 12, "B": 24, "C": 18, "D": 10, "E": 12, "F": 14}
for colonna, larghezza in larghezze.items():
    ws.column_dimensions[colonna].width = larghezza

ws.auto_filter.ref = ws.dimensions   # filtro su tutta la tabella
ws.freeze_panes = "A2"               # intestazione sempre visibile

openpyxl non ha un adattamento automatico delle colonne come il doppio clic di Excel, perché non conosce la larghezza reale dei caratteri. Si può approssimare calcolando la lunghezza del testo più lungo di ogni colonna, ma una tabella di larghezze fisse è spesso più semplice e prevedibile.

La riga dei totali

ultima = ws.max_row
ws.cell(row=ultima + 1, column=5, value="Totale").font = Font(bold=True)
ws.cell(row=ultima + 1, column=6, value=f"=SUM(F2:F{ultima})").font = Font(bold=True)

max_row restituisce l'ultima riga usata: il totale si adatta da solo al numero di righe di ogni settimana.

Aggiungere un grafico

openpyxl può inserire grafici nativi di Excel, modificabili da chi riceve il file:

from openpyxl.chart import BarChart, Reference

grafico = BarChart()
grafico.title = "Totale per vendita"
dati = Reference(ws, min_col=6, min_row=1, max_row=ultima)
categorie = Reference(ws, min_col=2, min_row=2, max_row=ultima)
grafico.add_data(dati, titles_from_data=True)
grafico.set_categories(categorie)
ws.add_chart(grafico, "H2")

Organizzare lo script

Nel mio lavoro divido sempre questi script in tre parti distinte: lettura dei dati, calcoli, scrittura del file. Se domani il gestionale cambia formato di esportazione, si modifica solo la prima parte; se il destinatario vuole un colore diverso, solo l'ultima. Conviene anche inserire la data nel nome del file, per esempio vendite_2025-03-10.xlsx, così le versioni non si sovrascrivono.

Obiettivo Strumento in openpyxl
Aggiungere righe ws.append()
Formato numeri e date cella.number_format
Stile intestazione Font, PatternFill, Alignment
Filtri ws.auto_filter.ref
Bloccare l'intestazione ws.freeze_panes
Grafici openpyxl.chart

In sintesi

  • openpyxl crea file Excel completi senza bisogno di Excel installato.
  • Le formule vengono scritte in inglese e calcolate all'apertura del file.
  • Usate date e numeri veri con number_format, non testo.
  • Intestazione formattata, filtri e riquadri bloccati rendono il report leggibile.
  • Separate lettura, calcoli e scrittura per uno script facile da mantenere.
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