Łączenie plików PDF w jeden dokument to jedna z najczęstszych automatyzacji biurowych. Przydaje się przy raportach, fakturach, umowach, dokumentacji projektowej, skanach, załącznikach do maili i materiałach archiwalnych. Zamiast ręcznie scalać pliki w edytorze PDF, możesz przygotować prosty skrypt w Pythonie, który zrobi to automatycznie, powtarzalnie i bez pomyłek w kolejności dokumentów.
Do łączenia PDF w Pythonie najlepiej sprawdza się biblioteka pypdf, czyli następca popularnego PyPDF2. Pozwala scalać wiele dokumentów, wybierać konkretne strony, ustawiać metadane, przetwarzać całe katalogi i obsługiwać błędy przy uszkodzonych plikach.
W tym artykule zobaczysz praktyczne przykłady: podstawowe łączenie PDF, batch merge z katalogu, sortowanie plików, wybór stron, ustawianie metadanych oraz bezpieczne scalanie z obsługą błędów.
Kurs Python od podstaw — PyStart
Zacznij programować w Pythonie od zera. Praktyczny kurs wideo z ćwiczeniami — bez wcześniejszego doświadczenia.
- ✓24 lekcje wideo + 80 ćwiczeń
- ✓Realne bazy z e-commerce
- ✓Społeczność i code-review
Instalacja biblioteki pypdf
Najpierw zainstaluj bibliotekę pypdf:
Bash1pip install pypdf
W starszych projektach możesz spotkać PyPDF2, ale w nowych skryptach lepiej używać pypdf. Ma podobny sposób działania, ale jest aktualniej rozwijany i wygodny w codziennej automatyzacji dokumentów.
Podstawowe łączenie plików PDF
Najprostszy przypadek to połączenie kilku znanych plików PDF w jeden dokument. Wystarczy utworzyć obiekt PdfMerger, dodać pliki przez append(), a potem zapisać wynik.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22from pypdf import PdfMerger def merge_pdfs(pdf_files: list[str], output_path: str): """Łączy wiele plików PDF w jeden dokument.""" merger = PdfMerger() for pdf_file in pdf_files: merger.append(pdf_file) merger.write(output_path) merger.close() print(f"Połączono {len(pdf_files)} plików PDF w: {output_path}") pdf_files = [ "dokument1.pdf", "dokument2.pdf", "dokument3.pdf" ] merge_pdfs(pdf_files, "polaczony_dokument.pdf")
Kolejność plików na liście ma znaczenie. Jeśli jako pierwszy podasz dokument1.pdf, jego strony znajdą się na początku wynikowego dokumentu.
Łączenie wszystkich PDF z katalogu
W praktyce często chcesz połączyć wszystkie pliki PDF znajdujące się w jednym folderze. Można to zrobić za pomocą pathlib, który ułatwia pracę ze ścieżkami.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29from pathlib import Path from pypdf import PdfMerger def batch_merge_pdfs(directory: str, output_path: str): """Łączy wszystkie pliki PDF z katalogu w kolejności alfabetycznej.""" pdf_dir = Path(directory) if not pdf_dir.exists(): raise FileNotFoundError(f"Katalog nie istnieje: {directory}") pdf_files = sorted(pdf_dir.glob("*.pdf")) if not pdf_files: print("Nie znaleziono plików PDF w katalogu.") return merger = PdfMerger() for pdf_file in pdf_files: print(f"Dodawanie: {pdf_file.name}") merger.append(str(pdf_file)) merger.write(output_path) merger.close() print(f"Połączono {len(pdf_files)} plików PDF w: {output_path}") batch_merge_pdfs("./pliki_pdf", "wszystkie_dokumenty.pdf")
To dobre rozwiązanie, gdy codziennie lub co tydzień dostajesz zestaw dokumentów do połączenia, np. faktury, raporty albo załączniki.
Sortowanie plików przed scaleniem
Sortowanie jest ważne, bo od niego zależy kolejność stron w końcowym PDF. Jeśli pliki nazywają się 1.pdf, 2.pdf, 10.pdf, zwykłe sortowanie alfabetyczne może dać kolejność 1.pdf, 10.pdf, 2.pdf.
Najlepiej nazywać pliki z zerami na początku:
1 2 3001_wstep.pdf 002_rozdzial.pdf 003_zalaczniki.pdf
Możesz też dodać sortowanie naturalne:
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32import re from pathlib import Path from pypdf import PdfMerger def natural_sort_key(path: Path): """Sortuje nazwy z liczbami w bardziej naturalnej kolejności.""" return [ int(part) if part.isdigit() else part.lower() for part in re.split(r"(\d+)", path.name) ] def batch_merge_pdfs_natural_sort(directory: str, output_path: str): pdf_dir = Path(directory) pdf_files = sorted(pdf_dir.glob("*.pdf"), key=natural_sort_key) if not pdf_files: print("Nie znaleziono plików PDF.") return merger = PdfMerger() for pdf_file in pdf_files: print(f"Dodawanie: {pdf_file.name}") merger.append(str(pdf_file)) merger.write(output_path) merger.close() print(f"Utworzono plik: {output_path}") batch_merge_pdfs_natural_sort("./pliki_pdf", "polaczony.pdf")
Dzięki temu pliki 1.pdf, 2.pdf i 10.pdf zostaną połączone w logicznej kolejności.
Łączenie PDF z ustawieniem metadanych
Kurs Python dla początkujących — PyStart
Zacznij programować w Pythonie! Idealne dla osób bez doświadczenia. Praktyczne zadania, projekty i wsparcie społeczności.
- ✓24 lekcje wideo + 80 ćwiczeń
- ✓Realne bazy z e-commerce
- ✓Społeczność i code-review
PDF może zawierać metadane, takie jak tytuł, autor, temat czy słowa kluczowe. Warto je ustawić, jeśli tworzysz raport, dokumentację lub plik do archiwum.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33from pypdf import PdfMerger def merge_with_metadata( pdf_files: list[str], output_path: str, title: str = "Połączony dokument", author: str = "Automatyzacja Python" ): """Łączy pliki PDF i ustawia metadane dokumentu.""" merger = PdfMerger() for pdf_file in pdf_files: merger.append(pdf_file) merger.add_metadata({ "/Title": title, "/Author": author, "/Subject": "Dokument wygenerowany automatycznie", "/Keywords": "PDF, Python, automatyzacja, scalanie" }) merger.write(output_path) merger.close() print(f"Utworzono dokument z metadanymi: {output_path}") merge_with_metadata( ["dok1.pdf", "dok2.pdf"], "raport_roczny.pdf", title="Raport roczny", author="System automatyzacji" )
Metadane ułatwiają późniejsze wyszukiwanie i porządkowanie dokumentów, szczególnie gdy pliki trafiają do archiwum, systemu DMS albo repozytorium firmowego.
Wybór konkretnych stron z plików PDF
Nie zawsze trzeba scalać całe dokumenty. Czasem potrzebujesz tylko wybranych stron: np. pierwszej strony z faktury, stron 2–5 z raportu albo załącznika z końca dokumentu.
W pypdf zakres stron jest indeksowany od zera. Oznacza to, że pierwsza strona ma indeks 0.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19from pypdf import PdfMerger def merge_page_ranges(output_path: str): """Łączy wybrane zakresy stron z różnych plików PDF.""" merger = PdfMerger() # Dodaje strony 1-3, czyli indeksy 0, 1, 2 merger.append("raport.pdf", pages=(0, 3)) # Dodaje strony 2-5, czyli indeksy 1, 2, 3, 4 merger.append("zalacznik.pdf", pages=(1, 5)) merger.write(output_path) merger.close() print(f"Utworzono plik: {output_path}") merge_page_ranges("wybrane_strony.pdf")
To przydatne, gdy tworzysz jeden dokument wynikowy z fragmentów kilku różnych PDF-ów.
Łączenie pojedynczych stron z różnych PDF
Jeśli chcesz wskazać konkretne strony, możesz użyć PdfReader i PdfWriter. To daje większą kontrolę niż PdfMerger.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36from pypdf import PdfReader, PdfWriter def merge_selected_pages(selection: dict[str, list[int]], output_path: str): """ Łączy konkretne strony z wielu plików PDF. selection: { "dokument1.pdf": [0, 2, 4], "dokument2.pdf": [1, 3] } """ writer = PdfWriter() for pdf_file, pages in selection.items(): reader = PdfReader(pdf_file) for page_number in pages: if page_number < len(reader.pages): writer.add_page(reader.pages[page_number]) else: print(f"Pominięto stronę {page_number} z pliku {pdf_file}") with open(output_path, "wb") as output_file: writer.write(output_file) print(f"Utworzono plik: {output_path}") merge_selected_pages( { "dokument1.pdf": [0, 2, 4], "dokument2.pdf": [0, 1] }, "wybrane_strony.pdf" )
Ten wzorzec sprawdza się, gdy chcesz budować dokument wynikowy z precyzyjnie wskazanych stron.
Bezpieczne łączenie PDF z obsługą błędów
W rzeczywistych folderach mogą znajdować się uszkodzone pliki, dokumenty z hasłem, puste pliki albo ścieżki, które już nie istnieją. Dobry skrypt powinien umieć pominąć problematyczny plik i kontynuować pracę.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42from pathlib import Path from pypdf import PdfMerger def safe_merge_pdfs(pdf_files: list[str], output_path: str): """Bezpiecznie łączy pliki PDF z obsługą błędów.""" merger = PdfMerger() successful = 0 failed = [] for pdf_file in pdf_files: path = Path(pdf_file) if not path.exists(): print(f"Ostrzeżenie: plik nie istnieje: {pdf_file}") failed.append(pdf_file) continue try: merger.append(str(path)) successful += 1 print(f"Dodano: {path.name}") except Exception as error: print(f"Błąd podczas dodawania {pdf_file}: {error}") failed.append(pdf_file) if successful > 0: merger.write(output_path) print(f"Połączono {successful} plików PDF w: {output_path}") if failed: print(f"Pominięto {len(failed)} plików: {failed}") else: print("Nie udało się połączyć żadnego pliku PDF.") merger.close() safe_merge_pdfs( ["dok1.pdf", "dok2.pdf", "nieistniejacy.pdf"], "bezpieczny_merge.pdf" )
Taki kod jest lepszy do automatyzacji niż prosty przykład bez obsługi błędów, bo nie zatrzymuje całego procesu przez jeden problematyczny dokument.
Pomijanie zaszyfrowanych PDF
Niektóre pliki PDF mogą być zabezpieczone hasłem. Wtedy zwykłe scalanie może zakończyć się błędem. Możesz wcześniej sprawdzić, czy dokument jest zaszyfrowany.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37from pathlib import Path from pypdf import PdfReader, PdfMerger def merge_skip_encrypted(directory: str, output_path: str): """Łączy pliki PDF z katalogu, pomijając zaszyfrowane dokumenty.""" pdf_dir = Path(directory) pdf_files = sorted(pdf_dir.glob("*.pdf")) merger = PdfMerger() skipped = [] for pdf_file in pdf_files: try: reader = PdfReader(str(pdf_file)) if reader.is_encrypted: print(f"Pominięto zaszyfrowany plik: {pdf_file.name}") skipped.append(pdf_file.name) continue merger.append(str(pdf_file)) print(f"Dodano: {pdf_file.name}") except Exception as error: print(f"Błąd pliku {pdf_file.name}: {error}") skipped.append(pdf_file.name) merger.write(output_path) merger.close() print(f"Utworzono: {output_path}") if skipped: print(f"Pominięte pliki: {skipped}") merge_skip_encrypted("./pliki_pdf", "polaczony_bez_zaszyfrowanych.pdf")
Jeśli znasz hasło do PDF, możesz go wcześniej odszyfrować lub otworzyć z hasłem, ale w automatyzacjach archiwalnych często lepiej takie pliki raportować i przekazać do ręcznej weryfikacji.
Dodanie zakładek do połączonego PDF
Przy większych dokumentach warto dodać zakładki, aby użytkownik łatwo przechodził do początku każdego scalonego pliku.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28from pathlib import Path from pypdf import PdfReader, PdfWriter def merge_with_bookmarks(pdf_files: list[str], output_path: str): """Łączy PDF-y i dodaje zakładkę na początku każdego pliku.""" writer = PdfWriter() current_page = 0 for pdf_file in pdf_files: reader = PdfReader(pdf_file) file_name = Path(pdf_file).stem writer.add_outline_item(file_name, current_page) for page in reader.pages: writer.add_page(page) current_page += 1 with open(output_path, "wb") as output_file: writer.write(output_file) print(f"Utworzono PDF z zakładkami: {output_path}") merge_with_bookmarks( ["01_wstep.pdf", "02_raport.pdf", "03_zalaczniki.pdf"], "dokument_z_zakladkami.pdf" )
Zakładki są szczególnie przydatne w dokumentacji, raportach, ofertach i większych pakietach plików.
Prosty skrypt CLI do łączenia PDF
Jeśli często łączysz PDF-y, możesz przygotować prosty skrypt uruchamiany z terminala. Dzięki temu podajesz katalog wejściowy i plik wynikowy jako argumenty.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32import argparse from pathlib import Path from pypdf import PdfMerger def merge_directory(input_dir: str, output_file: str): pdf_dir = Path(input_dir) pdf_files = sorted(pdf_dir.glob("*.pdf")) if not pdf_files: raise ValueError("Nie znaleziono plików PDF do połączenia.") merger = PdfMerger() for pdf_file in pdf_files: print(f"Dodawanie: {pdf_file.name}") merger.append(str(pdf_file)) merger.write(output_file) merger.close() print(f"Gotowe: {output_file}") def main(): parser = argparse.ArgumentParser(description="Łączenie plików PDF w jeden dokument.") parser.add_argument("input_dir", help="Katalog z plikami PDF") parser.add_argument("output_file", help="Ścieżka pliku wynikowego PDF") args = parser.parse_args() merge_directory(args.input_dir, args.output_file) if __name__ == "__main__": main()
Uruchomienie:
Bash1python merge_pdf.py ./pliki_pdf wynik.pdf
Taki skrypt możesz wykorzystać w codziennej pracy, harmonogramie zadań albo większym pipeline dokumentów.
Dobre praktyki przy łączeniu plików PDF
Przy automatycznym scalaniu dokumentów warto trzymać się kilku zasad:
- zapisuj plik wynikowy poza katalogiem wejściowym,
- sortuj pliki przed połączeniem,
- stosuj nazwy z numerami, np.
001_,002_,003_, - sprawdzaj, czy katalog zawiera pliki PDF,
- obsługuj błędy przy uszkodzonych dokumentach,
- raportuj pominięte pliki,
- nie nadpisuj oryginalnych dokumentów,
- dodawaj metadane do pliku wynikowego,
- przy dużych dokumentach rozważ dodanie zakładek,
- testuj skrypt na kopii plików.
Dzięki temu automatyzacja będzie bezpieczniejsza i łatwiejsza do utrzymania.
Podsumowanie
Python co tydzień — newsletter dla programistów
Otrzymuj codzienne ćwiczenia, ciekawostki z ekosystemu Pythona i wskazówki do rozmów rekrutacyjnych.
Łączenie plików PDF w Pythonie jest proste dzięki bibliotece pypdf. Możesz scalać pojedyncze dokumenty, przetwarzać całe katalogi, wybierać konkretne strony, ustawiać metadane, pomijać uszkodzone pliki i dodawać zakładki do dużych dokumentów.
Najważniejsze w praktycznej automatyzacji jest nie samo append(), ale kontrola kolejności plików, obsługa błędów i bezpieczne zapisywanie wyniku. Dzięki temu skrypt nadaje się nie tylko do jednorazowego użycia, ale też do codziennego przetwarzania raportów, faktur, skanów i dokumentacji.
Jeśli chcesz zacząć od prostego rozwiązania, przygotuj folder z plikami nazwanymi 001_, 002_, 003_, a następnie uruchom batch merge z sortowaniem. To najprostszy sposób na powtarzalne i bezpieczne scalanie PDF w Pythonie.
➡️ Następny artykuł
Po opanowaniu łączenia plików PDF poznaj techniki ich rozdzielania i manipulacji stronami:
Rozdzielanie i scalanie stron PDF w Pythonie — wycinanie zakresów stron, dzielenie dokumentów na rozdziały i zaawansowane techniki organizacji dużych dokumentów PDF.



