Il PDF è nato per essere stampato e letto, non per essere rielaborato. Chiunque abbia provato a copiare una tabella da un estratto conto o da un listino fornitore in un foglio di calcolo lo sa: le colonne si mescolano, i numeri finiscono su righe sbagliate, gli importi diventano testo. Quando l'operazione va ripetuta ogni mese, uno script Python con la libreria pdfplumber trasforma un'ora di copia e incolla in pochi secondi.
Prima domanda: il PDF contiene testo?
Esistono due famiglie di PDF molto diverse. I PDF digitali sono generati da un programma (un gestionale, Word, un portale bancario) e contengono il testo vero e proprio, con la posizione di ogni carattere. I PDF scansionati, invece, sono fotografie di pagine: dentro c'è solo un'immagine.
Il test più semplice è aprire il file e provare a selezionare una parola con il mouse. Se si evidenzia, il testo c'è. Se si seleziona l'intera pagina come un blocco, è un'immagine e prima serve l'OCR, il riconoscimento ottico dei caratteri. Tutto quello che segue riguarda i PDF digitali.
Installare pdfplumber ed estrarre il testo
pip install pdfplumber
pdfplumber legge ogni pagina e conosce la posizione di caratteri, linee e rettangoli. Per estrarre il testo semplice bastano poche righe:
import pdfplumber
with pdfplumber.open("listino.pdf") as pdf:
for pagina in pdf.pages:
print(pagina.extract_text())
Il risultato rispetta abbastanza bene l'ordine di lettura, ma su documenti impaginati a più colonne può mescolare i blocchi. In quei casi conviene ritagliare l'area di interesse con pagina.crop((x0, top, x1, bottom)) e lavorare solo su quella.
Estrarre le tabelle
Il punto di forza della libreria è extract_tables(), che restituisce ogni tabella come un elenco di righe, ciascuna un elenco di celle:
import csv
import pdfplumber
with pdfplumber.open("estratto.pdf") as pdf, \
open("movimenti.csv", "w", newline="", encoding="utf-8") as out:
scrittore = csv.writer(out, delimiter=";")
for pagina in pdf.pages:
for tabella in pagina.extract_tables():
for riga in tabella:
scrittore.writerow(riga)
Il punto e virgola come separatore è una scelta pratica: le versioni italiane di Excel aprono così il CSV direttamente nelle colonne giuste.
Quando la tabella non ha bordi
L'estrazione funziona meglio quando la tabella è disegnata con linee visibili, perché pdfplumber usa proprio le linee per capire dove iniziano e finiscono le celle. Molti documenti però allineano le colonne solo con gli spazi. In quel caso si cambia strategia passando delle impostazioni:
impostazioni = {
"vertical_strategy": "text",
"horizontal_strategy": "text",
}
tabelle = pagina.extract_tables(impostazioni)
Con la strategia text la libreria deduce le colonne dall'allineamento delle parole. È meno precisa e va verificata, ma su un documento sempre uguale, come il report mensile dello stesso fornitore, una volta trovate le impostazioni giuste funziona in modo stabile. Per il debug è molto utile pagina.to_image().debug_tablefinder(), che genera un'immagine con le celle individuate evidenziate.
Pulire i dati estratti
Il testo estratto quasi mai è pronto per i calcoli. Le operazioni tipiche di pulizia sono:
- intestazioni ripetute: in un documento di più pagine la riga di intestazione compare su ogni pagina e va scartata tranne la prima;
- celle vuote o
None: righe di separazione e totali parziali producono celle vuote da filtrare; - numeri in formato italiano:
1.234,56va convertito in1234.56togliendo il punto delle migliaia e sostituendo la virgola; - descrizioni su più righe: una descrizione lunga può spezzarsi su due righe della tabella; spesso si riconosce perché la seconda riga non ha data né importo, e va unita alla precedente.
def importo(testo):
return float(testo.replace(".", "").replace(",", "."))
Portare i dati in Excel
Se l'obiettivo finale è un foglio di calcolo, la libreria pandas semplifica l'ultimo passaggio: si costruisce un DataFrame dalle righe pulite e lo si salva con to_excel(), che richiede anche il pacchetto openpyxl. Il vantaggio rispetto al CSV è che i numeri restano numeri e le date possono essere convertite in vere date, pronte per filtri e tabelle pivot.
| Tipo di documento | Approccio consigliato |
|---|---|
| PDF digitale con tabelle a bordi | extract_tables() con impostazioni predefinite |
| PDF digitale senza bordi | Strategia text e verifica manuale |
| PDF a più colonne | crop() dell'area utile |
| PDF scansionato | OCR prima di qualsiasi estrazione |
Verificare sempre i totali
Un'estrazione automatica può perdere una riga senza dare alcun errore. Nel mio lavoro aggiungo sempre un controllo finale: sommo gli importi estratti e li confronto con il totale riportato nel documento. Se coincidono, l'estrazione è affidabile; se no, so esattamente quale pagina ricontrollare. È una verifica di due righe di codice che rende l'automazione degna di fiducia.
In sintesi
- Verificate prima se il PDF contiene testo: per le scansioni serve l'OCR.
pdfplumberestrae testo e tabelle conoscendo la posizione di ogni elemento.- Per tabelle senza bordi usate la strategia
texte controllate il risultato. - Pulite intestazioni ripetute, celle vuote e numeri in formato italiano.
- Confrontate sempre la somma estratta con il totale del documento.