是否有可能,使用Python,合并单独的PDF文件?

假设是这样,我需要进一步扩展它。我希望循环通过目录中的文件夹,并重复此过程。

我可能是得过其实了,但是否可以排除每个pdf文件中包含的一页(我的报告生成总是创建一个额外的空白页)。


当前回答

它是可能的,使用Python,合并单独的PDF文件?

Yes.

下面的例子将一个文件夹中的所有文件合并为一个新的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)

其他回答

可以使用PyPdf2s PdfMerger类。

文件连接

您可以使用append方法简单地连接文件。

from PyPDF2 import PdfMerger

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

merger = PdfMerger()

for pdf in pdfs:
    merger.append(pdf)

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

如果需要,可以传递文件句柄而不是文件路径。

文件合并

如果您希望对合并进行更细粒度的控制,可以使用PdfMerger的合并方法,该方法允许您在输出文件中指定插入点,这意味着您可以在文件中的任何位置插入页面。可以将append方法看作是一个合并,其中插入点是文件的末尾。

e.g.

merger.merge(2, pdf)

在这里,我们将整个pdf插入到输出中,但在第2页。

页面范围

如果希望控制从特定文件中追加哪些页面,可以使用pages关键字参数append和merge,以(start, stop[, step])的形式传递一个元组(类似于常规的range函数)。

e.g.

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

如果你指定了一个无效的范围,你会得到一个IndexError。

注意:另外,为了避免文件处于打开状态,当合并文件被写入时,应该调用pdffilemergeners关闭方法。这确保及时关闭所有文件(输入和输出)。遗憾的是pdffil急诊没有作为上下文管理器实现,所以我们可以使用with关键字,避免显式的关闭调用,并获得一些简单的异常安全。

您可能还想看看作为pypdf2的一部分提供的pdfcat脚本。您可以潜在地避免完全编写代码的需要。

PyPdf2 github还包括一些演示合并的示例代码。

PyMuPdf

另一个值得一看的库是PyMuPdf。合并同样简单。

从命令行:

python -m fitz join -o result.pdf file1.pdf file2.pdf file3.pdf

从代码中

import fitz

result = fitz.open()

for pdf in ['file1.pdf', 'file2.pdf', 'file3.pdf']:
    with fitz.open(pdf) as mfile:
        result.insert_pdf(mfile)
    
result.save("result.pdf")

有大量的选项,详细说明在项目维基。

注意:在旧版本的PyMuPDF中insert_pdf为insertPDF

Giovanni G. PY以一种简单易用的方式(至少对我来说)给出了答案:

import os
from PyPDF2 import PdfFileMerger

def merge_pdfs(export_dir, input_dir, folder):
    current_dir = os.path.join(input_dir, folder)
    pdfs = os.listdir(current_dir)
    
    merger = PdfFileMerger()
    for pdf in pdfs:
        merger.append(open(os.path.join(current_dir, pdf), 'rb'))

    with open(os.path.join(export_dir, folder + ".pdf"), "wb") as fout:
        merger.write(fout)

export_dir = r"E:\Output"
input_dir = r"E:\Input"
folders = os.listdir(input_dir)
[merge_pdfs(export_dir, input_dir, folder) for folder in folders];

您可以从PyPDF2模块使用pdffilemerge。

例如,要从路径列表中合并多个PDF文件,可以使用以下函数:

from PyPDF2 import PdfFileMerger

# pass the path of the output final file.pdf and the list of paths
def merge_pdf(out_path: str, extracted_files: list [str]):
    merger   = PdfFileMerger()
    
    for pdf in extracted_files:
        merger.append(pdf)

    merger.write(out_path)
    merger.close()

merge_pdf('./final.pdf', extracted_files)

这个函数从父文件夹中递归地获取所有文件:

import os

# pass the path of the parent_folder
def fetch_all_files(parent_folder: str):
    target_files = []
    for path, subdirs, files in os.walk(parent_folder):
        for name in files:
            target_files.append(os.path.join(path, name))
    return target_files 

# get a list of all the paths of the pdf
extracted_files = fetch_all_files('./parent_folder')

最后,使用这两个函数进行声明。可以包含多个文档的parent_folder_path,以及用于合并PDF的目的地的output_pdf_path:

# get a list of all the paths of the pdf
parent_folder_path = './parent_folder'
outup_pdf_path     = './final.pdf'

extracted_files = fetch_all_files(parent_folder_path)
merge_pdf(outup_pdf_path, extracted_files)

你可以从这里获得完整的代码(来源):如何使用Python合并PDF文档

下面是针对我的特定用例的最常见答案的时间比较:合并5个大单页pdf文件的列表。每个测试我都运行了两次。

(免责声明:我在Flask中运行这个函数,您的里程可能会有所不同)

博士TL;

pdfrw是我测试的3个pdf文件组合库中最快的一个。

PyPDF2

start = time.time()
merger = PdfFileMerger()
for pdf in all_pdf_obj:
    merger.append(
        os.path.join(
            os.getcwd(), pdf.filename # full path
                )
            )
formatted_name = f'Summary_Invoice_{date.today()}.pdf'
merge_file = os.path.join(os.getcwd(), formatted_name)
merger.write(merge_file)
merger.close()
end = time.time()
print(end - start) #1 66.50084733963013 #2 68.2995400428772

PyMuPDF

start = time.time()
result = fitz.open()

for pdf in all_pdf_obj:
    with fitz.open(os.path.join(os.getcwd(), pdf.filename)) as mfile:
        result.insertPDF(mfile)
formatted_name = f'Summary_Invoice_{date.today()}.pdf'

result.save(formatted_name)
end = time.time()
print(end - start) #1 2.7166640758514404 #2 1.694727897644043

PDFrw

start = time.time()
result = fitz.open()

writer = PdfWriter()
for pdf in all_pdf_obj:
    writer.addpages(PdfReader(os.path.join(os.getcwd(), pdf.filename)).pages)

formatted_name = f'Summary_Invoice_{date.today()}.pdf'
writer.write(formatted_name)
end = time.time()
print(end - start) #1 0.6040127277374268 #2 0.9576816558837891

def pdf_merger(路径): """将pdf文件合并为一个pdf""" "

import logging
logging.basicConfig(filename = 'output.log', level = logging.DEBUG, format = '%(asctime)s %(levelname)s %(message)s' )

try:
    import glob, os
    import PyPDF2
    
    os.chdir(path)
    
    pdfs = []
    
    for file in glob.glob("*.pdf"):
        pdfs.append(file)
        
    if len(pdfs) == 0:
        logging.info("No pdf in the given directory")
        
    else:
        merger = PyPDF2.PdfFileMerger()
        
        for pdf in pdfs:
            merger.append(pdf)
            
        merger.write('result.pdf')
        merger.close()
        
except Exception as e:
    logging.error('Error has happened')
    logging.exception('Exception occured' + str(e))