⟳ Automazione

Estrarre testo e tabelle da PDF con Python e pdfplumber

Come estrarre testo e tabelle da PDF digitali con Python e pdfplumber, salvarli in CSV o Excel e capire quando serve l'OCR per i documenti scansionati.

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,56 va convertito in 1234.56 togliendo 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.
  • pdfplumber estrae testo e tabelle conoscendo la posizione di ogni elemento.
  • Per tabelle senza bordi usate la strategia text e controllate il risultato.
  • Pulite intestazioni ripetute, celle vuote e numeri in formato italiano.
  • Confrontate sempre la somma estratta con il totale del documento.
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