2010-10-21 9 views
25

मैं कुछ पीडीएफ रूपों को संसाधित करने के लिए पाइथन का उपयोग करने की कोशिश कर रहा हूं जो Adobe Acrobat Reader का उपयोग करके भर चुके हैं और हस्ताक्षरित हैं।पायथन में एक भरे हुए फॉर्म से पीडीएफ फ़ील्ड निकालने के लिए कैसे?

मैं कोशिश की है:

  • pdfminer डेमो: यह डेटा बाहर भरा में से किसी डंप नहीं किया।
  • pyPdf: जब मैंने पीडीएफफ़ाइल रीडर (एफ) के साथ फ़ाइल लोड करने का प्रयास किया तो मैंने 2 मिनट के लिए कोर को अधिकतम किया और मैंने इसे छोड़ दिया और इसे मार दिया।
  • ज्योथन और PDFBox: यह बहुत अच्छा काम कर रहा है लेकिन स्टार्टअप समय अत्यधिक है, मैं सीधे जावा में बाहरी उपयोगिता लिखूंगा यदि यह मेरा एकमात्र विकल्प है।

मैं पुस्तकालयों के लिए शिकार रख सकता हूं और उन्हें कोशिश कर रहा हूं लेकिन मुझे उम्मीद है कि किसी के पास पहले से ही इसका एक कुशल समाधान है।


अद्यतन: स्टीवन के जवाब के आधार पर मैं pdfminer में देखा और यह चाल अच्छी तरह से किया था।

from argparse import ArgumentParser 
import pickle 
import pprint 
from pdfminer.pdfparser import PDFParser, PDFDocument 
from pdfminer.pdftypes import resolve1, PDFObjRef 

def load_form(filename): 
    """Load pdf form contents into a nested list of name/value tuples""" 
    with open(filename, 'rb') as file: 
     parser = PDFParser(file) 
     doc = PDFDocument() 
     parser.set_document(doc) 
     doc.set_parser(parser) 
     doc.initialize() 
     return [load_fields(resolve1(f)) for f in 
        resolve1(doc.catalog['AcroForm'])['Fields']] 

def load_fields(field): 
    """Recursively load form fields""" 
    form = field.get('Kids', None) 
    if form: 
     return [load_fields(resolve1(f)) for f in form] 
    else: 
     # Some field types, like signatures, need extra resolving 
     return (field.get('T').decode('utf-16'), resolve1(field.get('V'))) 

def parse_cli(): 
    """Load command line arguments""" 
    parser = ArgumentParser(description='Dump the form contents of a PDF.') 
    parser.add_argument('file', metavar='pdf_form', 
        help='PDF Form to dump the contents of') 
    parser.add_argument('-o', '--out', help='Write output to file', 
         default=None, metavar='FILE') 
    parser.add_argument('-p', '--pickle', action='store_true', default=False, 
         help='Format output for python consumption') 
    return parser.parse_args() 

def main(): 
    args = parse_cli() 
    form = load_form(args.file) 
    if args.out: 
     with open(args.out, 'w') as outfile: 
      if args.pickle: 
       pickle.dump(form, outfile) 
      else: 
       pp = pprint.PrettyPrinter(indent=2) 
       file.write(pp.pformat(form)) 
    else: 
     if args.pickle: 
      print pickle.dumps(form) 
     else: 
      pp = pprint.PrettyPrinter(indent=2) 
      pp.pprint(form) 

if __name__ == '__main__': 
    main() 
+0

एक नोट के रूप में, मैंने बाहरी उपयोगिता के रूप में पीडीएफटीके का उपयोग करने का भी प्रयास किया और यह मालिक पासवर्ड से पहले नहीं मिला। – Olson

उत्तर

25

आप pdfminer साथ यह करने के लिए सक्षम होना चाहिए, लेकिन यह ", शब्दकोश जैसे pdfminer के आंतरिक भागों में कुछ delving और पीडीएफ प्रारूप के बारे में कुछ ज्ञान (बेशक wrt रूपों, लेकिन यह भी पीडीएफ के आंतरिक संरचना के बारे में की आवश्यकता होगी "और" अप्रत्यक्ष वस्तुओं ")।

यह उदाहरण अपने रास्ते पर आप मदद कर सकता है (मुझे लगता है कि यह कोई एकत्रित फ़ील्ड आदि के साथ साधारण मामलों पर केवल काम करेंगे, ...)

import sys 
from pdfminer.pdfparser import PDFParser 
from pdfminer.pdfdocument import PDFDocument 
from pdfminer.pdftypes import resolve1 

filename = sys.argv[1] 
fp = open(filename, 'rb') 

parser = PDFParser(fp) 
doc = PDFDocument(parser) 
fields = resolve1(doc.catalog['AcroForm'])['Fields'] 
for i in fields: 
    field = resolve1(i) 
    name, value = field.get('T'), field.get('V') 
    print '{0}: {1}'.format(name, value) 

संपादित करें: यदि आप प्रदान करने की आवश्यकता: उल्लेख करना भूल गया एक पासवर्ड, इसे doc.initialize()

+0

यह चाल है, धन्यवाद। मैंने वेब डेमो देखा और लगा कि मैं देख सकता था कि मैं वहां क्या चाहता था और यदि नहीं, तो मैं इसे छोड़ सकता था। बाहर निकलता है न केवल यह वही तरीका कर सकता है जो मैं चाहता हूं, यह हस्ताक्षर फ़ील्ड को भी संभाल सकता है जो पीडीएफबॉक्स नहीं कर सकता है। – Olson

+1

मेरे पास एक एन्कोडिंग समस्या है। Field.get ('V') का उपयोग करना विशेष अक्षर जैसे 'ü' या 'ä' को एन्कोड नहीं करता है। क्या किसी के पास इसका कोई समाधान है? स्ट्रिंग को यूनिकोड में कनवर्ट करना एक डिकोडिंग त्रुटि उठाता है। – Basil

+2

पीडीएफमिनेर के वर्तमान संस्करण में PDFDocument.initialize विधि को हटा दिया गया है। यह कोड काम करता है अगर आप उस रेखा को हटा दें। लाइन 12 फ़ाइल "so_2.py",: – joshua

3

त्वरित और गंदे 2-मिनट की नौकरी पास करें; पीडीएफ को एक्सएमएल में कनवर्ट करने के लिए बस PDFminer का उपयोग करें और फिर सभी फ़ील्ड को पकड़ें।

from xml.etree import ElementTree 
from pprint import pprint 
import os 

def main(): 
    print "Calling PDFDUMP.py" 
    os.system("dumppdf.py -a FILE.pdf > out.xml") 

    # Preprocess the file to eliminate bad XML. 
    print "Screening the file" 
    o = open("output.xml","w") #open for append 
    for line in open("out.xml"): 
     line = line.replace("&#", "Invalid_XML") #some bad data in xml for formatting info. 
     o.write(line) 
    o.close() 

    print "Opening XML output" 
    tree = ElementTree.parse('output.xml') 
    lastnode = "" 
    lastnode2 = "" 
    list = {} 
    entry = {} 

    for node in tree.iter(): # Run through the tree..   
     # Check if New node 
     if node.tag == "key" and node.text == "T": 
      lastnode = node.tag + node.text 
     elif lastnode == "keyT": 
      for child in node.iter(): 
       entry["ID"] = child.text 
      lastnode = "" 

     if node.tag == "key" and node.text == "V": 
      lastnode2 = node.tag + node.text 
     elif lastnode2 == "keyV": 
      for child in node.iter(): 
       if child.tag == "string": 
        if entry.has_key("ID"): 
         entry["Value"] = child.text 
         list[entry["ID"]] = entry["Value"] 
         entry = {} 
      lastnode2 = "" 

    pprint(list) 

if __name__ == '__main__': 
    main() 

यह सुंदरता, अवधारणा का एक साधारण प्रमाण नहीं है। मुझे इसे जिस प्रणाली पर काम कर रहा है, उसके लिए इसे लागू करने की ज़रूरत है, इसलिए मैं इसे साफ कर दूंगा, लेकिन मैंने सोचा कि अगर कोई इसे उपयोगी पाता है तो मैं इसे पोस्ट करूंगा।

file.write(pp.pformat(form)) 

होना चाहिए::

3

पीडीएफ खान में काम करनेवाला (परिवर्तन आयात और पहले समारोह में पदव्याख्यायित्र/doc सेटअप) के नवीनतम संस्करण के लिए अद्यतन

from argparse import ArgumentParser 
import pickle 
import pprint 
from pdfminer.pdfparser import PDFParser 
from pdfminer.pdfdocument import PDFDocument 
from pdfminer.pdftypes import resolve1 
from pdfminer.pdftypes import PDFObjRef 

def load_form(filename): 
    """Load pdf form contents into a nested list of name/value tuples""" 
    with open(filename, 'rb') as file: 
     parser = PDFParser(file) 
     doc = PDFDocument(parser) 
     parser.set_document(doc) 
     #doc.set_parser(parser) 
     doc.initialize() 
     return [load_fields(resolve1(f)) for f in 
      resolve1(doc.catalog['AcroForm'])['Fields']] 

def load_fields(field): 
    """Recursively load form fields""" 
    form = field.get('Kids', None) 
    if form: 
     return [load_fields(resolve1(f)) for f in form] 
    else: 
     # Some field types, like signatures, need extra resolving 
     return (field.get('T').decode('utf-8'), resolve1(field.get('V'))) 

def parse_cli(): 
    """Load command line arguments""" 
    parser = ArgumentParser(description='Dump the form contents of a PDF.') 
    parser.add_argument('file', metavar='pdf_form', 
     help='PDF Form to dump the contents of') 
    parser.add_argument('-o', '--out', help='Write output to file', 
     default=None, metavar='FILE') 
    parser.add_argument('-p', '--pickle', action='store_true', default=False, 
     help='Format output for python consumption') 
    return parser.parse_args() 

def main(): 
    args = parse_cli() 
    form = load_form(args.file) 
    if args.out: 
     with open(args.out, 'w') as outfile: 
      if args.pickle: 
       pickle.dump(form, outfile) 
      else: 
       pp = pprint.PrettyPrinter(indent=2) 
       file.write(pp.pformat(form)) 
    else: 
     if args.pickle: 
      print pickle.dumps(form) 
     else: 
      pp = pprint.PrettyPrinter(indent=2) 
      pp.pprint(form) 

if __name__ == '__main__': 
    main() 
+0

आप फ़ाइल नाम कहां डालते हैं ताकि स्क्रिप्ट चल सके? – user2067030

0

इन पंक्तियों पर लिखने में कोई त्रुटि नहीं है

outfile.write(pp.pformat(form)) 
3

पायथन 3।6+:

pip install PyPDF2

# -*- 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()) 



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

    pdf_file_name = 'FormExample.pdf' 

    pprint(get_form_fields(pdf_file_name)) 
0

अजगर PyPDF2 पैकेज (pyPdf के उत्तराधिकारी) बहुत सुविधाजनक है:

import PyPDF2 
f = PyPDF2.PdfFileReader('form.pdf') 
ff = f.getFields() 

फिर ff एक dict कि सभी प्रासंगिक प्रपत्र में जानकारी शामिल है।

संबंधित मुद्दे