Как извлечь поля PDF из заполненной формы в Python?

Я пытаюсь использовать Python для обработки некоторых форм PDF, которые были заполнены и подписаны с помощью Adobe Acrobat Reader.

Я пробовал:

  • Демоверсия pdfminer : она не сбрасывала ни одну из заполненных данных.
  • pyPdf : он максимировал ядро в течение 2 минут, когда я попытался загрузить файл с PdfFileReader (f), и я просто сдался и убил его.
  • Jython и PDFBox : это отлично работает, но время запуска чрезмерно, я просто напишу внешнюю утилиту в прямой Java, если это мой единственный вариант.

Я могу продолжать охоту за библиотеками и попробовать их, но я надеюсь, что у кого-то есть эффективное решение для этого.


Обновление. Основываясь на ответе Стивена, я посмотрел в 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() 

5 Solutions collect form web for “Как извлечь поля PDF из заполненной формы в Python?”

Вы должны иметь возможность сделать это с помощью pdfminer , но это потребует некоторого углубления в внутренности pdfminer и некоторых знаний о формате pdf (например, в формах wrt, а также о внутренних структурах pdf, таких как словари и косвенные объекты) ,

Этот пример может помочь вам на вашем пути (я думаю, что он будет работать только в простых случаях, без вложенных полей и т. Д.)

 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) 

EDIT: забыл упомянуть: если вам нужно предоставить пароль, перейдите к doc.initialize()

Быстрая и грязная 2-минутная работа; просто используйте PDFminer для преобразования PDF в xml и затем захватите все поля.

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

Это не красиво, просто простое доказательство концепции. Мне нужно реализовать его для системы, над которой я работаю, поэтому я буду ее чистить, но я думал, что опубликую ее, если кто-нибудь найдет ее полезной.

Обновление последней версии pdf-шахтера (изменение импорта и настройка парсера / 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() 

Python 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)) 

На этих строках есть опечатка:

 file.write(pp.pformat(form)) 

Должно быть:

 outfile.write(pp.pformat(form)) 
  • Извлечение заголовков из файлов PDF?
  • Как продолжить содержание на следующей странице в Reportlabs - Python
  • Визуализация данных: лучшие инструменты для создания простых диаграмм в PDF с помощью Javascript или Python
  • Python tkinter сохранить холст как постскриптум и добавить в pdf
  • Acrobat JavaScript - преобразование ссылок на страницы JavaScript на «реальные ссылки»
  • matplotlib savefig bbox_inches = 'tight' не игнорирует невидимые оси
  • Пакетное преобразование .py (текстовые файлы) в .pdf на osx
  • Django / django-easy-pdf: объект «NoneType» не имеет атрибута «encode»
  • Изменение стиля вывода PDF-Latex через конвертер IPython для ноутбуков
  • Как создать PDF-файлы в Python
  • Генерация предварительного просмотра миниатюр Python PDF
  • Python - лучший язык программирования в мире.