是否有可能,使用Python,合并单独的PDF文件?
假设是这样,我需要进一步扩展它。我希望循环通过目录中的文件夹,并重复此过程。
我可能是得过其实了,但是否可以排除每个pdf文件中包含的一页(我的报告生成总是创建一个额外的空白页)。
是否有可能,使用Python,合并单独的PDF文件?
假设是这样,我需要进一步扩展它。我希望循环通过目录中的文件夹,并重复此过程。
我可能是得过其实了,但是否可以排除每个pdf文件中包含的一页(我的报告生成总是创建一个额外的空白页)。
当前回答
您也可以使用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中(然后,您可以选择不复制哪些页面。Pages对象的行为类似于一个列表)。
它仍然被积极维护,截至2022年2月,PyPDF2和pdfrw似乎都不是这种情况。
我还没有对它进行基准测试,所以我不知道它比其他解决方案更快还是更慢。
在我的例子中,与PyMuPDF相比的一个优点是有一个官方的Ubuntu包可用(python3-pikepdf),可以根据它来打包我自己的软件。
其他回答
使用字典以获得更大的灵活性(例如sort, dedup):
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")
您可以从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文档
使用正确的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()
您也可以使用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中(然后,您可以选择不复制哪些页面。Pages对象的行为类似于一个列表)。
它仍然被积极维护,截至2022年2月,PyPDF2和pdfrw似乎都不是这种情况。
我还没有对它进行基准测试,所以我不知道它比其他解决方案更快还是更慢。
在我的例子中,与PyMuPDF相比的一个优点是有一个官方的Ubuntu包可用(python3-pikepdf),可以根据它来打包我自己的软件。
下面是针对我的特定用例的最常见答案的时间比较:合并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