合并 PDF 文件

2025-01-21 09:01:00
admin
原创
78
摘要:问题描述:是否可以使用 Python 合并单独的 PDF 文件?假设如此,我需要进一步扩展这一点。我希望循环遍历目录中的文件夹并重复此过程。我可能有点运气不好,但是否有可能排除每个 PDF 中包含的页面(我的报告生成总是会创建一个额外的空白页)。解决方案 1:您可以使用pypdf类PdfMerger。文件连接...

问题描述:

是否可以使用 Python 合并单独的 PDF 文件?

假设如此,我需要进一步扩展这一点。我希望循环遍历目录中的文件夹并重复此过程。

我可能有点运气不好,但是否有可能排除每个 PDF 中包含的页面(我的报告生成总是会创建一个额外的空白页)。


解决方案 1:

您可以使用pypdf类PdfMerger

文件连接

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

from pypdf 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()

如果您愿意,您可以传递文件句柄而不是文件路径。

文件合并

如果您想要更精细地控制合并,可以使用merge的方法PdfMerger,它允许您在输出文件中指定插入点,这意味着您可以在文件中的任何位置插入页面。 该append方法可以被认为是 ,merge其中插入点是文件的末尾。

例如

merger.merge(2, pdf)

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

页面范围

如果您希望控制从特定文件附加哪些页面,则可以使用pages关键字参数appendand merge,以形式传递元组(start, stop[, step])(如常规range函数)。

例如

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

如果您指定了无效范围,您将得到一个IndexError

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

您可能还想查看pdfly catpypdf 开发人员提供的命令。这样您就可以完全避免编写代码。

pypdf 文档还包括一些演示合并的示例代码。

韓文

另一个值得一看的库是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")

有很多选项,详细信息请参阅项目wiki。

注意:在旧版本的 PyMuPDFinsert_pdfinsertPDF

解决方案 2:

使用Pypdf或其后续版本PyPDF2:

作为 PDF 工具包构建的纯 Python 库。它能够:

  • 逐页拆分文档,

  • 逐页合并文档,

(还有更多)

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

#!/usr/bin/env python
import sys
try:
    from PyPDF2 import PdfReader, PdfWriter
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 = PdfWriter()
        for reader in map(PdfReader, input_streams):
            for n in range(len(reader.pages)):
                writer.add_page(reader.pages[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)

解决方案 3:

合并目录中存在的所有 pdf 文件

将 pdf 文件放入目录中。启动程序。您将获得一个合并了所有 pdf 的 pdf。

import os
from PyPDF2 import PdfMerger

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

merger = PdfMerger()

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

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

我今天该如何编写上述相同的代码

from glob import glob
from PyPDF2 import PdfMerger



def pdf_merge():
    ''' Merges all the pdf files in current directory '''
    merger = PdfMerger()
    allpdfs = [a for a in glob("*.pdf")]
    [merger.append(pdf) for pdf in allpdfs]
    with open("Merged_pdfs.pdf", "wb") as new_file:
        merger.write(new_file)


if __name__ == "__main__":
    pdf_merge()

解决方案 4:

假设您不需要保留书签和注释,并且您的 PDF 未加密,则 该pdfrwcat.py可以非常轻松地做到这一点。是一个示例连接脚本,subset.py是一个示例页面子集脚本。

连接脚本的相关部分——假设inputs是输入文件名列表,并且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作者。

解决方案 5:

是否可以使用 Python 合并单独的 PDF 文件?

是的。

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

解决方案 6:

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

(免责声明:我在 Flask 中运行此功能,您的情况可能会有所不同)

总结

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

解决方案 7:

您也可以使用pikepdf(源代码 文档)。

示例代码可以是(取自文档):

from glob import glob

from pikepdf import Pdf

pdf = Pdf.new()

for file in glob('*.pdf'):  # you can change this to browse directories recursively
    with Pdf.open(file) as src:
        pdf.pages.extend(src.pages)

pdf.save('merged.pdf')
pdf.close()

如果您想排除页面,您可以采用另一种方式,例如将页面复制到新的 pdf(您可以选择不复制的页面,然后对象的pdf.pages行为就像一个列表)。

它仍在积极维护,但截至 2022 年 2 月,PyPDF2 和 pdfrw 似乎并非如此。

我还没有对它进行过基准测试,所以我不知道它是否比其他解决方案更快或更慢。

对我来说,与 PyMuPDF 相比,它的一个优势是有一个官方的 Ubuntu 包可用(python3-pikepdf),这对于根据它打包我自己的软件来说很实用。

解决方案 8:

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 仓库:https ://github.com/mahaguru24/Python_Merge_PDF.git

解决方案 9:

这里,http://pieceofpy.com/2009/03/05/concatenating-pdf-with-python/,给出了解决方案。

相似地:

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

------ 11月25日更新------

------ 似乎上面的代码不再起作用------

------ 请使用以下内容:------

from PyPDF2 import PdfFileMerger, PdfFileReader
import os

merger = PdfFileMerger()

file_folder = "C:\\My Ducoments\\\"

root, dirs, files = next(os.walk(file_folder))

for path, subdirs, files in os.walk(root):
    for f in files:
        if f.endswith(".pdf"):
            merger.append(file_folder + f)

merger.write(file_folder + "Economists-1.pdf")

解决方案 10:

为了获得更大的灵活性(例如排序、重复数据删除),稍微改变了一下字典:

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

解决方案 11:

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

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

解决方案 12:

PdfFileMerger您可以从PyPDF2模块使用。

例如,要合并路径列表中的多个 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')

最后,使用两个函数声明.a parent_folder_path(可以包含多个文档)和一个output_pdf_path作为合并 PDF 的目标:

# 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 文档

解决方案 13:

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];

解决方案 14:

PdfMerger已弃用并已在(版本 5.0.0)中删除pypdf。因此,如果您使用的是最新版本的pypdf,则需要使用模块PdfWriter中的类pypdf

from pypdf import PdfWriter

merger = PdfWriter()

for pdf in ["file1.pdf", "file2.pdf", "file3.pdf"]:
    merger.append(pdf)

merger.write("merged-pdf.pdf")
merger.close()

您可以参考此链接:
https: //pypdf.readthedocs.io/en/stable/user/merging-pdfs.html

解决方案 15:

def pdf_merger(path): """将多个 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))

解决方案 16:

使用正确的 Python 解释器:

conda activate py_envs

pip install PyPDF2

Python代码:

from PyPDF2 import PdfMerger

#set path files
import os
os.chdir('/ur/path/to/folder/')
cwd = os.path.abspath('')
files = os.listdir(cwd)

def merge_pdf_files():
    merger = PdfMerger()
    pdf_files = [x for x in files if x.endswith(".pdf")]
    [merger.append(pdf) for pdf in pdf_files]
    with open("merged_pdf_all.pdf", "wb") as new_file:
        merger.write(new_file)

if __name__ == "__main__":
    merge_pdf_files()
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用