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

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

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


当前回答

您可以从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文档

其他回答

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')

Go 回购:https://github.com/mahaguru24/Python_Merge_PDF.git

可以使用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

我在linux终端上通过利用subprocess(假设目录中存在one.pdf和two.pdf)使用pdf unite,目的是将它们合并为three.pdf

 import subprocess
 subprocess.call(['pdfunite one.pdf two.pdf three.pdf'],shell=True)

使用Pypdf或其后续版本PyPDF2:

作为PDF工具包构建的Pure-Python库。它能够: 逐页拆分文档, 逐页合并文件,

(以及更多)

下面是一个适用于这两个版本的示例程序。

#!/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
        # https://stackoverflow.com/questions/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()
        output_stream.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)

pdfrw库可以很容易地做到这一点,假设您不需要保存书签和注释,并且您的pdf文件没有加密。Cat.py是一个示例拼接脚本,而子集.py是一个示例页面子集脚本。

串联脚本的相关部分——假设input是一个输入文件名列表,outfn是一个输出文件名:

from pdfrw import PdfReader, PdfWriter

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

正如你所看到的,省略最后一页是很容易的,例如:

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

免责声明:我是pdfrw的主要作者。