将多个 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