2012-05-07 18 views
8

Tôi có một biểu mẫu PDF cần được điền vào một loạt thời gian (đó là biểu mẫu thời gian chính xác). Bây giờ vì tôi không muốn làm điều này bằng tay, tôi đang tìm cách để điền chúng bằng cách sử dụng một tập lệnh python hoặc các công cụ có thể được sử dụng trong một tập lệnh bash.Các biểu mẫu PDF điền hàng loạt từ trăn hoặc bash

Có ai có kinh nghiệm với điều này không?

+0

Xem http://stackoverflow.com/questions/1890570/how- can-i-auto-populate-a-pdf-form-in-django-python –

Trả lời

12

Đối với Python bạn sẽ cần lib fdfgen và pdftk

bình luận @Hugh Bothwell là chính xác 100% vì vậy tôi sẽ mở rộng mà câu trả lời với một thực hiện làm việc.

Nếu bạn đang ở trong cửa sổ, bạn cũng sẽ cần đảm bảo cả trăn và pdftk được chứa trong đường dẫn hệ thống (trừ khi bạn muốn sử dụng tên thư mục dài).

Dưới đây là đoạn code để tự động batch-điền vào một tập hợp các hình thức PDF từ một tệp dữ liệu CSV:

import csv 
from fdfgen import forge_fdf 
import os 
import sys 

sys.path.insert(0, os.getcwd()) 
filename_prefix = "NVC" 
csv_file = "NVC.csv" 
pdf_file = "NVC.pdf" 
tmp_file = "tmp.fdf" 
output_folder = './output/' 

def process_csv(file): 
    headers = [] 
    data = [] 
    csv_data = csv.reader(open(file)) 
    for i, row in enumerate(csv_data): 
     if i == 0: 
     headers = row 
     continue; 
     field = [] 
     for i in range(len(headers)): 
     field.append((headers[i], row[i])) 
     data.append(field) 
    return data 

def form_fill(fields): 
    fdf = forge_fdf("",fields,[],[],[]) 
    fdf_file = open(tmp_file,"w") 
    fdf_file.write(fdf) 
    fdf_file.close() 
    output_file = '{0}{1} {2}.pdf'.format(output_folder, filename_prefix, fields[1][1]) 
    cmd = 'pdftk "{0}" fill_form "{1}" output "{2}" dont_ask'.format(pdf_file, tmp_file, output_file) 
    os.system(cmd) 
    os.remove(tmp_file) 

data = process_csv(csv_file) 
print('Generating Forms:') 
print('-----------------------') 
for i in data: 
    if i[0][1] == 'Yes': 
    continue 
    print('{0} {1} created...'.format(filename_prefix, i[1][1])) 
    form_fill(i) 

Lưu ý: Không nên rocket-phẫu thuật để tìm ra cách để tùy chỉnh này. Các khai báo biến ban đầu chứa cấu hình tùy chỉnh.

Trong CSV, trong hàng đầu tiên, mỗi cột sẽ chứa tên của tên trường tương ứng trong tệp PDF. Bất kỳ cột nào không có các trường tương ứng trong mẫu sẽ bị bỏ qua.

Trong mẫu PDF, chỉ cần tạo trường có thể chỉnh sửa nơi bạn muốn dữ liệu của mình điền vào và đảm bảo các tên khớp với dữ liệu CSV.

Đối với cấu hình cụ thể này, chỉ cần đặt tệp này trong cùng thư mục với NVC.csv, NVC.pdf và thư mục có tên 'đầu ra'. Chạy nó và nó tự động làm phần còn lại.

+0

Công trình này đẹp mắt. Chỉ có điều tôi phải thêm là đường dẫn đến PDFtk: 'code'os.environ ['PATH'] + = os.pathsep + 'C: \\ Tệp chương trình (x86) \\ PDFtk \\ bin;' – Suzanne

0

Replace Original file

os.system('pdftk "original.pdf" fill_form "data.fdf" output "output.pdf"') 
os.remove("data.fdf") 
os.remove("original.pdf") 
os.rename("output.pdf","original.pdf") 
+0

Nó có thể là một bình luận cho câu trả lời ở trên. –

3

nhanh hơn nhiều phiên bản, không có cũng không pdftk fdfgen cần thiết, Python tinh khiết 3.6+:

# -*- coding: utf-8 -*- 

from collections import OrderedDict 
from PyPDF2 import PdfFileWriter, PdfFileReader 


def _getFields(obj, tree=None, retval=None, fileobj=None): 
    """ 
    Extracts field data if this PDF contains interactive form fields. 
    The *tree* and *retval* parameters are for recursive use. 

    :param fileobj: A file object (usually a text file) to write 
     a report to on all interactive form fields found. 
    :return: A dictionary where each key is a field name, and each 
     value is a :class:`Field<PyPDF2.generic.Field>` object. By 
     default, the mapping name is used for keys. 
    :rtype: dict, or ``None`` if form data could not be located. 
    """ 
    fieldAttributes = {'/FT': 'Field Type', '/Parent': 'Parent', '/T': 'Field Name', '/TU': 'Alternate Field Name', 
         '/TM': 'Mapping Name', '/Ff': 'Field Flags', '/V': 'Value', '/DV': 'Default Value'} 
    if retval is None: 
     retval = OrderedDict() 
     catalog = obj.trailer["/Root"] 
     # get the AcroForm tree 
     if "/AcroForm" in catalog: 
      tree = catalog["/AcroForm"] 
     else: 
      return None 
    if tree is None: 
     return retval 

    obj._checkKids(tree, retval, fileobj) 
    for attr in fieldAttributes: 
     if attr in tree: 
      # Tree is a field 
      obj._buildField(tree, retval, fileobj, fieldAttributes) 
      break 

    if "/Fields" in tree: 
     fields = tree["/Fields"] 
     for f in fields: 
      field = f.getObject() 
      obj._buildField(field, retval, fileobj, fieldAttributes) 

    return retval 


def get_form_fields(infile): 
    infile = PdfFileReader(open(infile, 'rb')) 
    fields = _getFields(infile) 
    return OrderedDict((k, v.get('/V', '')) for k, v in fields.items()) 


def update_form_values(infile, outfile, newvals=None): 
    pdf = PdfFileReader(open(infile, 'rb')) 
    writer = PdfFileWriter() 

    for i in range(pdf.getNumPages()): 
     page = pdf.getPage(i) 
     try: 
      if newvals: 
       writer.updatePageFormFieldValues(page, newvals) 
      else: 
       writer.updatePageFormFieldValues(page, 
               {k: f'#{i} {k}={v}' 
                for i, (k, v) in enumerate(get_form_fields(infile).items()) 
                }) 
      writer.addPage(page) 
     except Exception as e: 
      print(repr(e)) 
      writer.addPage(page) 

    with open(outfile, 'wb') as out: 
     writer.write(out) 


if __name__ == '__main__': 
    from pprint import pprint 

    pdf_file_name = '2PagesFormExample.pdf' 

    pprint(get_form_fields(pdf_file_name)) 

    update_form_values(pdf_file_name, 'out-' + pdf_file_name) # enumerate & fill the fields with their own names 
    update_form_values(pdf_file_name, 'out2-' + pdf_file_name, 
         {'my_fieldname_1': 'My Value', 
         'my_fieldname_2': 'My Another alue'}) # update the form fields 
+0

Điều này thật tuyệt vời !!! Cảm ơn bạn vì câu trả lời dễ dàng này – SmittySmee

+0

hiển thị lỗi cú pháp ở đây {k: f '# {i} {k} = {v}'. sử dụng python 3.5. đó là lý do? –

Các vấn đề liên quan