Scal pliki PDF

126

Czy za pomocą Pythona można scalić oddzielne pliki PDF?

Zakładając tak, muszę to nieco rozszerzyć. Mam nadzieję, że przejdę w pętlę przez foldery w katalogu i powtórzę tę procedurę.

I może mam szczęście, ale czy można wykluczyć stronę zawartą w plikach PDF (generowanie raportu zawsze tworzy dodatkową pustą stronę).

Btibert3
źródło

Odpowiedzi:

122

Użyj Pypdf lub jego następcy PyPDF2 :

Biblioteka Pure-Python zbudowana jako zestaw narzędzi PDF. Jest w stanie:
* dzielić dokumenty strona po stronie,
* scalać dokumenty strona po stronie,

(i wiele więcej)

Oto przykładowy program, który działa z obiema wersjami.

#!/usr/bin/env python
import sys
try:
    from PyPDF2 import PdfFileReader, PdfFileWriter
except ImportError:
    from pyPdf import PdfFileReader, PdfFileWriter

def pdf_cat(input_files, output_stream):
    input_streams = []
    try:
        # First open all the files, then produce the output file, and
        # finally close the input files. This is necessary because
        # the data isn't read from the input files until the write
        # operation. Thanks to
        # /programming/6773631/problem-with-closing-python-pypdf-writing-getting-a-valueerror-i-o-operation/6773733#6773733
        for input_file in input_files:
            input_streams.append(open(input_file, 'rb'))
        writer = PdfFileWriter()
        for reader in map(PdfFileReader, input_streams):
            for n in range(reader.getNumPages()):
                writer.addPage(reader.getPage(n))
        writer.write(output_stream)
    finally:
        for f in input_streams:
            f.close()

if __name__ == '__main__':
    if sys.platform == "win32":
        import os, msvcrt
        msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    pdf_cat(sys.argv[1:], sys.stdout)
Gilles 'SO- przestań być zły'
źródło
19
A teraz pypi.python.org/pypi/PyPDF2, który jest następcą projektu PyPDF
David Fraser
U mnie działa tylko z otwieraniem w trybie binarnym (strumienie wejściowe, a także strumień wyjściowy). open(input_file), 'r+b'i zamiast sys.stdout używam output_stream = open('result.pdf', 'w+b').
Simeon Borko
@SimeonBorko Upuść +, to znaczy „czytaj i pisz” i żaden plik nie jest jednocześnie czytany i zapisywany. Dodałem obsługę wyjścia Windows w oparciu o stackoverflow.com/questions/2374427/… .
SO- Gilles 'SO- przestań być zły'
PyPDF2 / 3 nie jest stabilny, jak mogę scalić pliki pdf bez PyPDF2 / 3.
GoingMyWay
2
Musiałem użyć sys.stdout.bufferPythona 3.6.8 (Linux)
Greyshack
197

Można użyć PyPdf2 s PdfMergerklasę.

Łączenie plików

Możesz po prostu połączyć pliki za pomocą appendmetody.

from PyPDF2 import PdfFileMerger

pdfs = ['file1.pdf', 'file2.pdf', 'file3.pdf', 'file4.pdf']

merger = PdfFileMerger()

for pdf in pdfs:
    merger.append(pdf)

merger.write("result.pdf")
merger.close()

Jeśli chcesz, możesz przekazać uchwyty plików zamiast ścieżek do plików.

Łączenie plików

Jeśli chcesz dokładniejszej kontroli scalania, istnieje mergemetoda PdfMerger, która pozwala określić punkt wstawiania w pliku wyjściowym, co oznacza, że ​​możesz wstawić strony w dowolnym miejscu pliku. appendMetoda może być traktowane jako mergegdzie punkt wstawiania jest koniec pliku.

na przykład

merger.merge(2, pdf)

Tutaj wstawiamy cały plik PDF do wyjścia, ale na stronie 2.

Zakresy stron

Jeśli chcesz kontrolować, które strony są dołączane z określonego pliku, możesz użyć pagesargumentu słowa kluczowego appendi merge, przekazując krotkę w formularzu (start, stop[, step])(podobnie jak zwykła rangefunkcja).

na przykład

merger.append(pdf, pages=(0, 3))    # first 3 pages
merger.append(pdf, pages=(0, 6, 2)) # pages 1,3, 5

Jeśli określisz nieprawidłowy zakres, otrzymasz plik IndexError.

Uwaga: aby uniknąć pozostawienia otwartych plików, po PdfFileMergerzapisaniu scalonego pliku należy wywołać metodę s close. Zapewnia to terminowe zamykanie wszystkich plików (wejściowych i wyjściowych). Szkoda, że PdfFileMergernie jest zaimplementowany jako menedżer kontekstu, więc możemy użyć withsłowa kluczowego, uniknąć jawnego zamknięcia i uzyskać łatwe zabezpieczenie wyjątków.

Możesz również spojrzeć na pdfcatskrypt dostarczony jako część pypdf2. Możesz potencjalnie całkowicie uniknąć konieczności pisania kodu.

Github PyPdf2 zawiera również przykładowy kod demonstrujący łączenie.

Paul Rooney
źródło
14

Scal wszystkie pliki pdf, które są obecne w katalogu

Umieść pliki pdf w katalogu. Uruchom program. Otrzymasz jeden plik PDF ze scalonymi wszystkimi plikami PDF.

import os
from PyPDF2 import PdfFileMerger

x = [a for a in os.listdir() if a.endswith(".pdf")]

merger = PdfFileMerger()

for pdf in x:
    merger.append(open(pdf, 'rb'))

with open("result.pdf", "wb") as fout:
    merger.write(fout)
Giovanni G. PY
źródło
8

pdfrwBiblioteka może to zrobić dość łatwo, zakładając, że nie trzeba zachować zakładek i notatek, a Twoje pliki PDF nie są szyfrowane. cat.pyto przykładowy skrypt konkatenacji i subset.pyprzykładowy skrypt określający podzbiory strony.

Odpowiednia część skryptu konkatenacji - zakłada, że inputsjest to lista nazw plików wejściowych i outfnjest nazwą pliku wyjściowego:

from pdfrw import PdfReader, PdfWriter

writer = PdfWriter()
for inpfn in inputs:
    writer.addpages(PdfReader(inpfn).pages)
writer.write(outfn)

Jak widać z tego, bardzo łatwo byłoby pominąć ostatnią stronę, np. Coś takiego:

    writer.addpages(PdfReader(inpfn).pages[:-1])

Zastrzeżenie: jestem głównym pdfrwautorem.

Patrick Maupin
źródło
1
To jest najbardziej stabilny.
GoingMyWay
1
Ta biblioteka zasługuje na większą reputację.
GoingMyWay
6

Czy za pomocą Pythona można scalić oddzielne pliki PDF?

Tak.

Poniższy przykład scala wszystkie pliki w jednym folderze w jeden nowy plik PDF:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from argparse import ArgumentParser
from glob import glob
from pyPdf import PdfFileReader, PdfFileWriter
import os

def merge(path, output_filename):
    output = PdfFileWriter()

    for pdffile in glob(path + os.sep + '*.pdf'):
        if pdffile == output_filename:
            continue
        print("Parse '%s'" % pdffile)
        document = PdfFileReader(open(pdffile, 'rb'))
        for i in range(document.getNumPages()):
            output.addPage(document.getPage(i))

    print("Start writing '%s'" % output_filename)
    with open(output_filename, "wb") as f:
        output.write(f)

if __name__ == "__main__":
    parser = ArgumentParser()

    # Add more options if you like
    parser.add_argument("-o", "--output",
                        dest="output_filename",
                        default="merged.pdf",
                        help="write merged PDF to FILE",
                        metavar="FILE")
    parser.add_argument("-p", "--path",
                        dest="path",
                        default=".",
                        help="path of source PDF files")

    args = parser.parse_args()
    merge(args.path, args.output_filename)
Martin Thoma
źródło
3
from PyPDF2 import PdfFileMerger
import webbrowser
import os
dir_path = os.path.dirname(os.path.realpath(__file__))

def list_files(directory, extension):
    return (f for f in os.listdir(directory) if f.endswith('.' + extension))

pdfs = list_files(dir_path, "pdf")

merger = PdfFileMerger()

for pdf in pdfs:
    merger.append(open(pdf, 'rb'))

with open('result.pdf', 'wb') as fout:
    merger.write(fout)

webbrowser.open_new('file://'+ dir_path + '/result.pdf')

Git Repo: https://github.com/mahaguru24/Python_Merge_PDF.git

guruprasad mulay
źródło
2

tutaj, http://pieceofpy.com/2009/03/05/concatenating-pdf-with-python/ , podaje rozwiązanie.

podobnie:

from pyPdf import PdfFileWriter, PdfFileReader

def append_pdf(input,output):
    [output.addPage(input.getPage(page_num)) for page_num in range(input.numPages)]

output = PdfFileWriter()

append_pdf(PdfFileReader(file("C:\\sample.pdf","rb")),output)
append_pdf(PdfFileReader(file("c:\\sample1.pdf","rb")),output)
append_pdf(PdfFileReader(file("c:\\sample2.pdf","rb")),output)
append_pdf(PdfFileReader(file("c:\\sample3.pdf","rb")),output)

    output.write(file("c:\\combined.pdf","wb"))
Mark K.
źródło
0

Niewielka zmiana przy użyciu słownika dla większej elastyczności (np. Sortowanie, deduplikacja):

import os
from PyPDF2 import PdfFileMerger
# use dict to sort by filepath or filename
file_dict = {}
for subdir, dirs, files in os.walk("<dir>"):
    for file in files:
        filepath = subdir + os.sep + file
        # you can have multiple endswith
        if filepath.endswith((".pdf", ".PDF")):
            file_dict[file] = filepath
# use strict = False to ignore PdfReadError: Illegal character error
merger = PdfFileMerger(strict=False)

for k, v in file_dict.items():
    print(k, v)
    merger.append(v)

merger.write("combined_result.pdf")
Ogaga Uzoh
źródło
0

Użyłem pdf unite na terminalu linux, wykorzystując podproces (zakładając, że jeden.pdf i dwa.pdf istnieją w katalogu), a celem jest połączenie ich w trzy.pdf

 import subprocess
 subprocess.call(['pdfunite one.pdf two.pdf three.pdf'],shell=True)
user8291021
źródło