2012-05-07 25 views
8

私は一度にたくさんの記入が必要なPDFフォームを用意しています(正確にはタイムシートです)。私は手でこれをやりたくないので、私は、bashスクリプトで使うことができるpythonスクリプトやツールを使ってそれらを埋める方法を探していました。pythonまたはbashからPDFフォームを一括入力

誰もこの経験がありますか? Python用

+0

がhttp://stackoverflow.com/questions/1890570/how-を参照しcan-i-auto-populate-a-pdf-form-in-django-python –

答えて

12

あなたはfdfgenのlibが必要とpdftkます

@Hughボスウェルさんのコメントは、私が働い実装とその答えを拡張します100%正確です。

Windowsの場合、長いフォルダ名を使用しない限り、pythonとpdftkの両方がシステムパスに含まれていることを確認する必要があります。

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) 

注:

はここでCSVデータファイルからのPDFフォームのコレクションを自動バッチフィルへのコードのITは、これをカスタマイズする方法を見つけ出すためにロケット手術ではありません。初期変数宣言にはカスタム構成が含まれています。

CSVでは、最初の行に各列にPDFファイルの対応するフィールド名の名前が含まれます。テンプレートに対応するフィールドを持たない列は無視されます。

PDFテンプレートでは、データを入力して名前がCSVデータと一致するように編集可能なフィールドを作成するだけです。

この特定の構成では、このファイルをNVC.csv、NVC.pdf、および 'output'という名前のフォルダと同じフォルダに配置します。それを実行し、それは自動的に残りを行います。

+0

これは美しく動作します。私が追加しなければならなかったのは、PDFtkへの道でした: 'code'os.environ ['PATH'] + = os.pathsep + 'C:\\ Program Files(x86)\\ PDFtk \\ bin; – Suzanne

0

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

これはおそらく上記の答えに対するコメントであることを意図していました。 –

3

はるかに高速バージョン、無pdftkもfdfgen必要な、純粋なPythonの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

これは素晴らしいです!この簡単な答えをありがとうございます – SmittySmee

+0

はここで構文エラーを示しています{k:f '#{i} {k} = {v}'。 pythonを使って3.5。その理由は何ですか? –

関連する問題