将多个 pdf 文件中的特定页面写入一个新的 pdf 文件
Write specific pages from multiple pdf files to a new pdf file
我有多个 pdf 文件,我想从中提取一组特定页面,每个 pdf 文件的每组页面都不同。我创建了一个字典,其中键作为 pdf 文件名,值作为要从每个 pdf 文件中提取的页面列表(显示为键)。我打算从相关的 pdf 文件中提取给定的页面,并将它们全部写入一个新的 pdf 文件,以便我可以对这个最终文件进行数据提取。我已经尝试过 PyPDF4 和 FPDF,但目前还没有任何乐趣,因为它给了我一个带有空白页的大 pdf 或一个仅提取了 1 或 2 页的 pdf 或找不到 pdf 对象的错误。我希望就我的方法哪里出了问题得到一些指导。下面是我的代码:
import PyPDF4
from PyPDF4 import PdfFileReader, PdfFileWriter
for pdf,pgs in dic_11_1.items():
pdf=list(dic_11_1.keys())
pgs=list(dic_11_1.values())
for i in range(0,len(pdf)):
pages = pgs[i]
object = open(pdf[i],'rb')
pdfinput=PyPDF4.PdfFileReader(object,'rb')
if pdfinput.isEncrypted:
pdfinput.decrypt('')
else:
pdfinput
for p in pages:
page=pdfinput.getPage(p)
pdf_writer=PyPDF4.PdfFileWriter()
pdf_writer.addPage(page)
with open('F111.pdf',mode='wb') as output:
pdf_writer.write(output)
我得到的错误是 'PdfReadError: Could not find object.'
当我使用以下代码尝试 FPDF 时,它运行了很长时间,并给我一个很大的空 pdf 文件:
from fpdf import FPDF
import os
for pdf,pgs in dic_11_1.items():
pdf_in=open(pdf,'rb')
inputpdf=PdfFileReader(pdf_in,'rb')
if inputpdf.isEncrypted:
inputpdf.decrypt('')
else:
inputpdf
for p in pgs:
content=inputpdf.getPage(p).extractText()
pdf = FPDF('P','mm','A4')
pdf.add_page()
pdf.set_font("arial", size = 10)
for text in content:
text2=text.encode('latin-1', 'replace').decode('latin-1')
pdf.write(10,text2)
pdf.ln(8)
pdf.close()
return_byte_string=pdf.output('F_11_1.pdf','S').encode('latin-1')
pdf_file=open('F_11_1.pdf','wb')
pdf_file.write(return_byte_string)
pdf_file.close()
任何指导将不胜感激。提前谢谢你
@SUTerliakov 提供的解决方案很棒,但只写了页面字典值列表中的最后一页或最后一个文档。它通过代码中的一个小缩进得到解决,并为我获取了所有数据。再次感谢@SUTerliakov 让我走上了正确的道路!这是您调整后的代码:
pdf_writer = PdfFileWriter()
open_files = []
try:
for filename, pgs in dic_11_1.items():
src = open(filename, 'rb')
open_files.append(src)
pdfinput = PdfFileReader(src, 'rb')
if pdfinput.isEncrypted:
pdfinput.decrypt('')
print(f'Extracting relevant pages from {filename} to central repository')
for p in pgs:
print(f'{filename} pg{str(p)}')
pdf_writer.addPage(pdfinput.getPage(p))
print(f'Writing {len(pgs)} pages to central file')
Stream=open('F_11_1.pdf','wb')
pdf_writer.write(Stream)
finally:
print('Closing Source File...')
for f in open_files:
f.close()
嗯,问题是你没有正确迭代。请参阅代码中的注释以更好地理解。
更新。 PyPDF4
似乎只添加对 PdfFileWriter
的页面引用,直到它实际写入某个文件。所以我们只能在最后关闭输入源。因此,此方法不适用于大文件数(在 linux 上它将受到 ulimit
的限制,默认情况下为 1024,因此我们只能打开 1000 个输入文件 + 1 个输出文件 + 3 个系统流- stdin, stdout, stderr;这个限制可以用 ulimit -n <count>
).
扩大
from PyPDF4 import PdfFileReader, PdfFileWriter
sect_11_1 = [
('filename1.pdf', 0, 1),
('filename2.pdf', 0, 1),
]
# note pages are zero-numbered
dic_11_1 = {}
# if sect_11_1 is of another format
# [('filename', [0, 1]), ...]
# remove star below
for filename, *pages in sect_11_1:
dic_11_1.setdefault(filename, [])
dic_11_1[filename].extend(pages)
# if filenames are not repeated, you can do just
# dic_11_1 = dict(sect_11_1)
# you need single writer for all files, don't declare it in a loop
pdf_writer = PdfFileWriter()
open_files = []
try:
for filename, pages in dic_11_1.items():
# now you have filename and pages set to 'filename1.pdf' and [1, 3, 4]
# on second iteration they'll be set to 'filename2.pdf' and [0, 2, 3]
# ...
# don't use `object` as variable name: it's valid, but bad style
# (it shadows builtin `object`)
src = open(filename, 'rb')
open_files.append(src)
pdfinput = PdfFileReader(src, 'rb')
if pdfinput.isEncrypted:
pdfinput.decrypt('')
# you don't need empty `else`
for p in pages:
# you might want to use `p - 1` instead if your input was 1-numbered
page = pdfinput.getPage(p)
pdf_writer.addPage(page)
# when all pages are added, write to output
with open('F111.pdf',mode='wb') as output:
pdf_writer.write(output)
finally: # if something was wrong, do it anyway
for f in open_files:
f.close() # we shouldn't keep files open after program run
我有多个 pdf 文件,我想从中提取一组特定页面,每个 pdf 文件的每组页面都不同。我创建了一个字典,其中键作为 pdf 文件名,值作为要从每个 pdf 文件中提取的页面列表(显示为键)。我打算从相关的 pdf 文件中提取给定的页面,并将它们全部写入一个新的 pdf 文件,以便我可以对这个最终文件进行数据提取。我已经尝试过 PyPDF4 和 FPDF,但目前还没有任何乐趣,因为它给了我一个带有空白页的大 pdf 或一个仅提取了 1 或 2 页的 pdf 或找不到 pdf 对象的错误。我希望就我的方法哪里出了问题得到一些指导。下面是我的代码:
import PyPDF4
from PyPDF4 import PdfFileReader, PdfFileWriter
for pdf,pgs in dic_11_1.items():
pdf=list(dic_11_1.keys())
pgs=list(dic_11_1.values())
for i in range(0,len(pdf)):
pages = pgs[i]
object = open(pdf[i],'rb')
pdfinput=PyPDF4.PdfFileReader(object,'rb')
if pdfinput.isEncrypted:
pdfinput.decrypt('')
else:
pdfinput
for p in pages:
page=pdfinput.getPage(p)
pdf_writer=PyPDF4.PdfFileWriter()
pdf_writer.addPage(page)
with open('F111.pdf',mode='wb') as output:
pdf_writer.write(output)
我得到的错误是 'PdfReadError: Could not find object.'
当我使用以下代码尝试 FPDF 时,它运行了很长时间,并给我一个很大的空 pdf 文件:
from fpdf import FPDF
import os
for pdf,pgs in dic_11_1.items():
pdf_in=open(pdf,'rb')
inputpdf=PdfFileReader(pdf_in,'rb')
if inputpdf.isEncrypted:
inputpdf.decrypt('')
else:
inputpdf
for p in pgs:
content=inputpdf.getPage(p).extractText()
pdf = FPDF('P','mm','A4')
pdf.add_page()
pdf.set_font("arial", size = 10)
for text in content:
text2=text.encode('latin-1', 'replace').decode('latin-1')
pdf.write(10,text2)
pdf.ln(8)
pdf.close()
return_byte_string=pdf.output('F_11_1.pdf','S').encode('latin-1')
pdf_file=open('F_11_1.pdf','wb')
pdf_file.write(return_byte_string)
pdf_file.close()
任何指导将不胜感激。提前谢谢你
@SUTerliakov 提供的解决方案很棒,但只写了页面字典值列表中的最后一页或最后一个文档。它通过代码中的一个小缩进得到解决,并为我获取了所有数据。再次感谢@SUTerliakov 让我走上了正确的道路!这是您调整后的代码:
pdf_writer = PdfFileWriter()
open_files = []
try:
for filename, pgs in dic_11_1.items():
src = open(filename, 'rb')
open_files.append(src)
pdfinput = PdfFileReader(src, 'rb')
if pdfinput.isEncrypted:
pdfinput.decrypt('')
print(f'Extracting relevant pages from {filename} to central repository')
for p in pgs:
print(f'{filename} pg{str(p)}')
pdf_writer.addPage(pdfinput.getPage(p))
print(f'Writing {len(pgs)} pages to central file')
Stream=open('F_11_1.pdf','wb')
pdf_writer.write(Stream)
finally:
print('Closing Source File...')
for f in open_files:
f.close()
嗯,问题是你没有正确迭代。请参阅代码中的注释以更好地理解。
更新。 PyPDF4
似乎只添加对 PdfFileWriter
的页面引用,直到它实际写入某个文件。所以我们只能在最后关闭输入源。因此,此方法不适用于大文件数(在 linux 上它将受到 ulimit
的限制,默认情况下为 1024,因此我们只能打开 1000 个输入文件 + 1 个输出文件 + 3 个系统流- stdin, stdout, stderr;这个限制可以用 ulimit -n <count>
).
from PyPDF4 import PdfFileReader, PdfFileWriter
sect_11_1 = [
('filename1.pdf', 0, 1),
('filename2.pdf', 0, 1),
]
# note pages are zero-numbered
dic_11_1 = {}
# if sect_11_1 is of another format
# [('filename', [0, 1]), ...]
# remove star below
for filename, *pages in sect_11_1:
dic_11_1.setdefault(filename, [])
dic_11_1[filename].extend(pages)
# if filenames are not repeated, you can do just
# dic_11_1 = dict(sect_11_1)
# you need single writer for all files, don't declare it in a loop
pdf_writer = PdfFileWriter()
open_files = []
try:
for filename, pages in dic_11_1.items():
# now you have filename and pages set to 'filename1.pdf' and [1, 3, 4]
# on second iteration they'll be set to 'filename2.pdf' and [0, 2, 3]
# ...
# don't use `object` as variable name: it's valid, but bad style
# (it shadows builtin `object`)
src = open(filename, 'rb')
open_files.append(src)
pdfinput = PdfFileReader(src, 'rb')
if pdfinput.isEncrypted:
pdfinput.decrypt('')
# you don't need empty `else`
for p in pages:
# you might want to use `p - 1` instead if your input was 1-numbered
page = pdfinput.getPage(p)
pdf_writer.addPage(page)
# when all pages are added, write to output
with open('F111.pdf',mode='wb') as output:
pdf_writer.write(output)
finally: # if something was wrong, do it anyway
for f in open_files:
f.close() # we shouldn't keep files open after program run