Python中搜索和替换PDF中的文本

17 浏览
0 Comments

Python中搜索和替换PDF中的文本

这个问题已经有了答案:

如何使用Python替换PDF中的文本?

作为Python Web应用程序的一部分,我正在编写邮件合并软件。

我有一个称为letter.pdf的模板,它是从一个MS Word文件生成的,并包含文本{name},其中居民的姓名将出现。 我还有一个约100名居民姓名的列表。

我想要做的是读取letter.pdf,搜索\"{name}\",并用居民的姓名替换它(对于每个居民),然后将结果写入另一个PDF中。 然后,我想将所有这些PDF文件聚合到一个大PDF文件中(每封信一张纸),我的Web应用程序的用户将打印出来以创建他们的信件。

是否有任何Python库可以做到这一点? 我已经看过pdfrw和pdfminer,但我看不到它们能实现这一点的地方。

(NB:我还有MS Word文件,因此如果还有其他使用它而不是通过PDF进行的方法,那也可以完成工作。)

admin 更改状态以发布 2023年5月22日
0
0 Comments

如果@Dmytrio的解决方案不改变最终PDF文件

Dymitrio的更新代码示例可以处理包含要更新的文本数据流的DecodedStreamObject和EncodedStreamObject,但是在使用不同于示例的文件时,无法更改PDF文本内容。

根据编辑3,来自如何使用Python替换PDF中的文本?:

writer.addPage(page)之前插入page [NameObject(“/Contents”)] = contents.decodedSelf,我们强制pyPDF2更新页面对象的内容。

这样,我能够解决这个问题,并替换PDF文件中的文本。

最终代码应该像这样:

import os
import argparse
from PyPDF2 import PdfFileReader, PdfFileWriter
from PyPDF2.generic import DecodedStreamObject, EncodedStreamObject, NameObject
def replace_text(content, replacements = dict()):
    lines = content.splitlines()
    result = ""
    in_text = False
    for line in lines:
        if line == "BT":
            in_text = True
        elif line == "ET":
            in_text = False
        elif in_text:
            cmd = line[-2:]
            if cmd.lower() == 'tj':
                replaced_line = line
                for k, v in replacements.items():
                    replaced_line = replaced_line.replace(k, v)
                result += replaced_line + "\n"
            else:
                result += line + "\n"
            continue
        result += line + "\n"
    return result
def process_data(object, replacements):
    data = object.getData()
    decoded_data = data.decode('utf-8')
    replaced_data = replace_text(decoded_data, replacements)
    encoded_data = replaced_data.encode('utf-8')
    if object.decodedSelf is not None:
        object.decodedSelf.setData(encoded_data)
    else:
        object.setData(encoded_data)
if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--input", required=True, help="path to PDF document")
    args = vars(ap.parse_args())
    in_file = args["input"]
    filename_base = in_file.replace(os.path.splitext(in_file)[1], "")
    # Provide replacements list that you need here
    replacements = { 'PDF': 'DOC'}
    pdf = PdfFileReader(in_file)
    writer = PdfFileWriter()
    for page_number in range(0, pdf.getNumPages()):
        page = pdf.getPage(page_number)
        contents = page.getContents()
        if isinstance(contents, DecodedStreamObject) or isinstance(contents, EncodedStreamObject):
            process_data(contents, replacements)
        elif len(contents) > 0:
            for obj in contents:
                if isinstance(obj, DecodedStreamObject) or isinstance(obj, EncodedStreamObject):
                    streamObj = obj.getObject()
                    process_data(streamObj, replacements)
        # Force content replacement
        page[NameObject("/Contents")] = contents.decodedSelf
        writer.addPage(page)
    with open(filename_base + ".result.pdf", 'wb') as out_file:
        writer.write(out_file)

重要提示:from PyPDF2.generic import NameObject

0
0 Comments

这可以通过使用 PyPDF2 包来完成。实现可能取决于原始 PDF 模板的结构。但如果模板足够稳定,并且不经常更改,替换代码就不应该是通用的,而是简单的。

我画了一个小草图,说明如何替换 PDF 文件 中的文本。它将所有出现的 PDF 标记替换为 DOC

import os
import argparse
from PyPDF2 import PdfFileReader, PdfFileWriter
from PyPDF2.generic import DecodedStreamObject, EncodedStreamObject
def replace_text(content, replacements = dict()):
    lines = content.splitlines()
    result = ""
    in_text = False
    for line in lines:
        if line == "BT":
            in_text = True
        elif line == "ET":
            in_text = False
        elif in_text:
            cmd = line[-2:]
            if cmd.lower() == 'tj':
                replaced_line = line
                for k, v in replacements.items():
                    replaced_line = replaced_line.replace(k, v)
                result += replaced_line + "\n"
            else:
                result += line + "\n"
            continue
        result += line + "\n"
    return result
def process_data(object, replacements):
    data = object.getData()
    decoded_data = data.decode('utf-8')
    replaced_data = replace_text(decoded_data, replacements)
    encoded_data = replaced_data.encode('utf-8')
    if object.decodedSelf is not None:
        object.decodedSelf.setData(encoded_data)
    else:
        object.setData(encoded_data)
if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--input", required=True, help="path to PDF document")
    args = vars(ap.parse_args())
    in_file = args["input"]
    filename_base = in_file.replace(os.path.splitext(in_file)[1], "")
    # Provide replacements list that you need here
    replacements = { 'PDF': 'DOC'}
    pdf = PdfFileReader(in_file)
    writer = PdfFileWriter()
    for page_number in range(0, pdf.getNumPages()):
        page = pdf.getPage(page_number)
        contents = page.getContents()
        if isinstance(contents, DecodedStreamObject) or isinstance(contents, EncodedStreamObject):
            process_data(contents, replacements)
        elif len(contents) > 0:
            for obj in contents:
                if isinstance(obj, DecodedStreamObject) or isinstance(obj, EncodedStreamObject):
                    streamObj = obj.getObject()
                    process_data(streamObj, replacements)
        writer.addPage(page)
    with open(filename_base + ".result.pdf", 'wb') as out_file:
        writer.write(out_file)

结果如下

Original PDF
Replaced PDF

更新 2021-03-21:

更新了代码示例,以处理实际包含要更新文本的数据流的 DecodedStreamObjectEncodedStreamObject

0