⟳ Automazione

Unire, dividere e ruotare PDF con Python e pypdf

Come unire, dividere, ruotare ed estrarre pagine da file PDF con Python e la libreria pypdf, con esempi pronti per pratiche, fatture e scansioni d'ufficio.

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 try i file danneggiati, che altrimenti interrompono l'intera elaborazione;
  • ricordare che pypdf manipola pagine, non testo: per modificare il contenuto di una pagina servono altri strumenti.

In sintesi

  • pypdf permette di unire, dividere, ruotare e riordinare PDF in locale, senza caricarli online.
  • PdfReader legge le pagine, PdfWriter costruisce 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.
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