使用 PyPDF2 for Python 时,如何将 CSV 格式的数据传输到具有空白表单字段的现有 PDF?

问题描述 投票:0回答:1

我目前正在使用 Python 的 PyPDF2 扩展,并拥有我的数据(最初是 Google 表单),然后以 CSV 文件的形式下载,我希望将此数据复制到现有的 PDF 中,其字段与原始 Google 表单类似,但会不统一。在 PyPDF2 网站上,他们提供了一些示例(https://pypdf2.readthedocs.io/en/3.0.0/user/forms.html),但似乎他们正在创建一个全新的 PDF 以将原始数据移入而不是现有的 PDF。我是不是误读了他们的代码?

这是我到目前为止的代码。我知道前几行直到“读取现有的 PDF 文件...”起作用,并且它们按照列表的意思显示 CSV 文件,但之后我刚刚输入了 PyPDF2 网站上的代码,并添加了一些更具描述性的内容试图理解它的评论。使用 PyPDF2 查找现有 PDF 中的表单字段并使用 for 循环迭代 CSV 文件以插入匹配信息是否有意义?

import csv
from PyPDF2 import PdfReader, PdfWriter

# opens csv file and returns a file object - type of file is “_io.TextIOWrapper”
file = open("AfF.csv")
csvreader = csv.reader(file)

# creates an empty list called header and obtains the header from each row
header = next(csvreader)
print(header)

# iterates through csvobject and append each row to the rows list
rows = []
for row in csvreader:
    rows.append(row)
print(rows)

# reads an existing PDF file "form.pdf" that contains fillable form fields
reader = PdfReader("form.pdf")
fields = reader.get_form_text_fields() # extracts text fields from the PDF form, stores extracted form fields in the "fields" variable
fields == {"key": "value", "key2": "value2"} # fields will contain a dictionary mapping field names (keys) to their corresponding curret values (value) in the PDF form


# fills out form fields in PDF "form.pdf" and saves the filled PDF as "filled-out.pdf"
reader = PdfReader("form.pdf") # instantiates "PdfReader" object "reader" for reading the existing PDF file
writer = PdfWriter() #instatiates "PdfWriter" object "writer" for creating a new PDF

page = reader.pages[0] # retrieves the first page of pdf
fields = reader.get_fields() # gets all form fields from the PDF

writer.add_page(page) # add the retrieved page (page) to the PdfWriter object (writer) using writer.add_page(page)

writer.update_page_form_field_values( # uses this to update the form field values on the first page (writer.page[0]) with a dictionary specifying field names and their new values {"fieldname": "some filled in text"} 
    writer.pages[0], {"fieldname": "some filled in text"} 
)

# write "output" to PyPDF2-output.pdf
with open("filled-out.pdf", "wb") as output_stream: # write the modified pdf to "filled-out.pdf" by opening a binary file "wb" and using writer.write(output_stream)
    writer.write(output_stream)
python-3.x csv pdf pypdf
1个回答
0
投票

该示例使用阅读器打开一个 PDF,然后将其复制给编写器。 此步骤是强制性的,因为您无法使用 PyPDF2 打开 PDF 进行“编辑”。示例代码还将其保存到另一个文件,在磁盘上创建一个副本。 我想说这个例子遵循一个空白 PDF 的模式,其中的字段用作 template,并且他们希望您想要基于动态数据创建填充的副本。 我想,根据您的 Google 表单数据,您需要每行提交的表单值一个 PDF。 如果是这样,请继续阅读。

此外,如果您不需要专门使用 PyPDF2,请考虑 pypdf:PyPDF2 的工作已更改为 pypdf。阅读pypdf:回归根源(2023 年至今)

为了让初学者更简单,PyPDF2 被合并回 pypdf。现在全部小写,没有数字。我们希望开发 PyPDF3 和 PyPDF4 的人们也加入我们。

排除了这一点...我会从尽可能简单的开始,然后逐步向上。

我创建了这个简单的 PDF(您可以下载并跟随),只有两个字段:名称和最喜欢的颜色:

Empty form

我将使用 pypdf 来获取字段名称:

from pypdf import PdfReader

reader = PdfReader("form.pdf")
page = reader.pages[0]
fields = reader.get_fields()

print(fields)

我得到:

{
    'Name': {'/T': 'Name', '/FT': '/Tx'},
    'Fav_color': {'/T': 'Fav_color', '/FT': '/Tx'}
}

{'/T' ...}
部分并不重要,只是关键名称、Name和Fav_color。

然后使用该阅读器并尝试更新名称和 Fav_color:

from pypdf import PdfWriter

writer = PdfWriter()
writer.append(reader)

fields = {"Name": "Alice", "Fav_color": "blue"}

writer.update_page_form_field_values(
    writer.pages[0],
    fields,
    auto_regenerate=False,
)

with open("filled-out.pdf", "wb") as output_stream:
    writer.write(output_stream)

我打开filled-out.pdf,它看起来像:

Filled-out PDF

这样就成功了!然后,我尝试将其捆绑在一个函数中,让我指定一个新名称以及要使用的字段值:

def fill_out_pdf(new_name: str, fields: dict[str, str]):
    reader = PdfReader("form.pdf")
    page = reader.pages[0]

    writer = PdfWriter()
    writer.append(reader)

    writer.update_page_form_field_values(
        writer.pages[0],
        fields,
        auto_regenerate=False,
    )

    with open(new_name, "wb") as output_stream:
        writer.write(output_stream)


fill_out_pdf("filled-out.pdf", {"Name": "Alice", "Fav_color": "blue"})

看起来和上面一样。

从那里,我可以继续尝试集成 CSV 中的动态数据:

Name,Favorite color
Alice,blue
Bobbie,blue
Charlie,vermilion

为了在本示例中保持简单,我将使用 csv.reader 并将行中的 CSV 字段位置(从 0 开始)映射到 PDF 字段名称,0 → 名称,1 → 最喜欢的颜色:

import csv

with open("input.csv", newline="") as f:
    reader = csv.reader(f)
    next(reader)  # skip header
    rows = list(reader)

for row in rows:
    name = row[0]
    fav_color = row[1]

    new_name = f"{name}.pdf"
    fields = {"Name": name, "Fav_color": fav_color}

    fill_out_pdf(new_name, fields)

当我运行该程序时,我会得到三个 PDF,如下所示:

All PDFs filled out

尽管如此,这是一个非常简单的示例:只是一个 PDF 页面,PDF 本身没有问题。

这种工作很快就会变得棘手,因为 PDF 本身的问题可能意味着任何字段都可能看起来错误。我参与的一个项目中,300 多个字段中的一个字段在保存的填写版本中无法正确呈现:显然不是 Python 程序的问题……只是 PDF 中深层的问题。所以,请注意,祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.