In quasi ogni ufficio arriva il momento in cui bisogna mettere insieme dieci PDF in un unico fascicolo, separare un documento di cento pagine in tanti file singoli o raddrizzare una scansione caricata al contrario. Esistono servizi online che lo fanno, ma caricare contratti o documenti di identità su un sito sconosciuto non è una buona idea. Con Python e la libreria pypdf le stesse operazioni si eseguono sul proprio computer, in modo ripetibile e senza limiti sul numero di file.
Installazione e primo contatto
pypdf è una libreria scritta interamente in Python, senza dipendenze esterne per le operazioni di base. Si installa con:
pip install pypdf
Gli oggetti principali sono due: PdfReader, che apre un file esistente e ne espone le pagine, e PdfWriter, che costruisce un nuovo documento. Quasi tutte le operazioni consistono nel leggere pagine da uno o più reader e aggiungerle a un writer.
from pypdf import PdfReader
reader = PdfReader("contratto.pdf")
print(len(reader.pages), "pagine")
Unire più PDF in un unico file
Il caso più comune: una cartella con allegati da consegnare come documento unico. L'ordine conta, quindi conviene ordinarli esplicitamente, ad esempio per nome.
from pathlib import Path
from pypdf import PdfWriter
writer = PdfWriter()
for pdf in sorted(Path("allegati").glob("*.pdf")):
writer.append(str(pdf))
with open("fascicolo.pdf", "wb") as f:
writer.write(f)
Il metodo append aggiunge tutte le pagine del file e, nelle versioni recenti della libreria, ne conserva anche i segnalibri. Se i file sono numerati come 1.pdf, 2.pdf, 10.pdf, l'ordinamento alfabetico metterà 10 prima di 2: il rimedio è dare nomi con zeri iniziali (01, 02, 10) oppure ordinare in base al numero estratto dal nome.
Dividere un PDF in file separati
L'operazione inversa serve, per esempio, quando lo scanner produce un unico PDF con tutte le fatture del mese. Per creare un file per pagina:
from pypdf import PdfReader, PdfWriter
reader = PdfReader("scansione_mese.pdf")
for numero, pagina in enumerate(reader.pages, start=1):
writer = PdfWriter()
writer.add_page(pagina)
with open(f"pagina_{numero:03d}.pdf", "wb") as f:
writer.write(f)
Spesso però i documenti non sono di una pagina sola. In quel caso si definiscono gli intervalli: ad esempio pagine 1-3 per il primo documento, 4-4 per il secondo, 5-9 per il terzo. Un piccolo elenco di tuple, magari letto da un foglio di calcolo compilato da un collega, rende lo script riutilizzabile senza toccare il codice.
intervalli = [("ordine_A", 1, 3), ("ordine_B", 4, 4), ("ordine_C", 5, 9)]
for nome, inizio, fine in intervalli:
writer = PdfWriter()
for i in range(inizio - 1, fine):
writer.add_page(reader.pages[i])
with open(f"{nome}.pdf", "wb") as f:
writer.write(f)
Notate il inizio - 1: le persone contano le pagine da 1, Python da 0. È l'errore più frequente in questi script.
Ruotare le pagine storte
Le scansioni fatte di fretta contengono spesso pagine capovolte o in orizzontale. Ogni pagina ha un metodo rotate che accetta multipli di 90 gradi:
for i, pagina in enumerate(reader.pages):
if i in {2, 5}:
pagina.rotate(180)
writer.add_page(pagina)
La rotazione è un'indicazione per il visualizzatore, non una rielaborazione dell'immagine: il file non perde qualità e l'operazione è istantanea anche su documenti pesanti.
Estrarre, riordinare ed eliminare pagine
Con la stessa logica si può costruire un nuovo documento scegliendo solo alcune pagine o cambiandone l'ordine. Eliminare la pagina bianca finale che molti scanner aggiungono equivale a copiare tutte le pagine tranne l'ultima. Mettere la copertina in fondo significa aggiungere prima le pagine dalla seconda in poi e poi la prima.
| Operazione | Idea di base |
|---|---|
| Unire | append di più file nello stesso writer |
| Dividere | Un writer nuovo per ogni intervallo |
| Ruotare | rotate(90), rotate(180) sulla pagina |
| Eliminare | Copiare tutte le pagine tranne quelle indesiderate |
| Riordinare | Aggiungere le pagine nell'ordine voluto |
PDF protetti da password
Alcuni PDF sono cifrati. PdfReader lo segnala con l'attributo is_encrypted; se conoscete la password, potete sbloccare il file con reader.decrypt("password") e poi procedere come al solito. Si tratta di documenti di cui si ha legittimamente la password, per esempio estratti conto scaricati dalla propria banca: la libreria non serve, né deve servire, ad aggirare protezioni altrui. Allo stesso modo PdfWriter può cifrare il risultato con il metodo encrypt, utile quando il fascicolo contiene dati personali e deve viaggiare via email.
Buone pratiche
Nel mio lavoro tengo sempre separati originali e risultati: lo script legge da una cartella originali e scrive in una cartella elaborati, senza mai sovrascrivere i file di partenza. Altre accortezze utili:
- verificare che il numero di pagine finale sia quello atteso, stampando
len(writer.pages); - dare ai file prodotti nomi che contengano data e descrizione, così da ritrovarli facilmente;
- gestire con un blocco
tryi file danneggiati, che altrimenti interrompono l'intera elaborazione; - ricordare che
pypdfmanipola pagine, non testo: per modificare il contenuto di una pagina servono altri strumenti.
In sintesi
pypdfpermette di unire, dividere, ruotare e riordinare PDF in locale, senza caricarli online.PdfReaderlegge le pagine,PdfWritercostruisce il nuovo documento.- Attenzione alla numerazione: le persone partono da 1, Python da 0.
- La rotazione non degrada la qualità ed è istantanea.
- Tenete separati originali ed elaborati e controllate il numero di pagine finale.