Чи є модуль python для перетворення PDF-файлів у текст? Я спробував один фрагмент коду, знайдений в Activestate, який використовує pypdf, але генерований текст не мав місця між ними і не мав користі.
Чи є модуль python для перетворення PDF-файлів у текст? Я спробував один фрагмент коду, знайдений в Activestate, який використовує pypdf, але генерований текст не мав місця між ними і не мав користі.
Відповіді:
Спробуйте PDFMiner . Він може витягувати текст з PDF-файлів у форматі HTML, SGML або "PDF з міткою".
Формат з тегами PDF видається найчистішим, а викреслення тегів XML залишає лише головий текст.
Версія Python 3 доступна під:
Пакет PDFMiner змінився з моменту публікації кодексу .
EDIT (знову):
PDFMiner знову оновлений у версії 20100213
Ви можете перевірити встановлену версію за допомогою наступного:
>>> import pdfminer
>>> pdfminer.__version__
'20100213'
Ось оновлена версія (з коментарями до того, що я змінив / додав):
def pdf_to_csv(filename):
from cStringIO import StringIO #<-- added so you can copy/paste this to try it
from pdfminer.converter import LTTextItem, TextConverter
from pdfminer.pdfparser import PDFDocument, PDFParser
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
class CsvConverter(TextConverter):
def __init__(self, *args, **kwargs):
TextConverter.__init__(self, *args, **kwargs)
def end_page(self, i):
from collections import defaultdict
lines = defaultdict(lambda : {})
for child in self.cur_item.objs:
if isinstance(child, LTTextItem):
(_,_,x,y) = child.bbox #<-- changed
line = lines[int(-y)]
line[x] = child.text.encode(self.codec) #<-- changed
for y in sorted(lines.keys()):
line = lines[y]
self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
self.outfp.write("\n")
# ... the following part of the code is a remix of the
# convert() function in the pdfminer/tools/pdf2text module
rsrc = PDFResourceManager()
outfp = StringIO()
device = CsvConverter(rsrc, outfp, codec="utf-8") #<-- changed
# becuase my test documents are utf-8 (note: utf-8 is the default codec)
doc = PDFDocument()
fp = open(filename, 'rb')
parser = PDFParser(fp) #<-- changed
parser.set_document(doc) #<-- added
doc.set_parser(parser) #<-- added
doc.initialize('')
interpreter = PDFPageInterpreter(rsrc, device)
for i, page in enumerate(doc.get_pages()):
outfp.write("START PAGE %d\n" % i)
interpreter.process_page(page)
outfp.write("END PAGE %d\n" % i)
device.close()
fp.close()
return outfp.getvalue()
Редагувати (ще раз):
Ось оновлення для останньої версії в PyPI , 20100619p1
. Коротше я замінив LTTextItem
з LTChar
і передав примірник LAParams конструктору CsvConverter.
def pdf_to_csv(filename):
from cStringIO import StringIO
from pdfminer.converter import LTChar, TextConverter #<-- changed
from pdfminer.layout import LAParams
from pdfminer.pdfparser import PDFDocument, PDFParser
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
class CsvConverter(TextConverter):
def __init__(self, *args, **kwargs):
TextConverter.__init__(self, *args, **kwargs)
def end_page(self, i):
from collections import defaultdict
lines = defaultdict(lambda : {})
for child in self.cur_item.objs:
if isinstance(child, LTChar): #<-- changed
(_,_,x,y) = child.bbox
line = lines[int(-y)]
line[x] = child.text.encode(self.codec)
for y in sorted(lines.keys()):
line = lines[y]
self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
self.outfp.write("\n")
# ... the following part of the code is a remix of the
# convert() function in the pdfminer/tools/pdf2text module
rsrc = PDFResourceManager()
outfp = StringIO()
device = CsvConverter(rsrc, outfp, codec="utf-8", laparams=LAParams()) #<-- changed
# becuase my test documents are utf-8 (note: utf-8 is the default codec)
doc = PDFDocument()
fp = open(filename, 'rb')
parser = PDFParser(fp)
parser.set_document(doc)
doc.set_parser(parser)
doc.initialize('')
interpreter = PDFPageInterpreter(rsrc, device)
for i, page in enumerate(doc.get_pages()):
outfp.write("START PAGE %d\n" % i)
if page is not None:
interpreter.process_page(page)
outfp.write("END PAGE %d\n" % i)
device.close()
fp.close()
return outfp.getvalue()
EDIT (ще раз):
Оновлено для версії 20110515
(спасибі Oeufcoque Penteano!):
def pdf_to_csv(filename):
from cStringIO import StringIO
from pdfminer.converter import LTChar, TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfparser import PDFDocument, PDFParser
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
class CsvConverter(TextConverter):
def __init__(self, *args, **kwargs):
TextConverter.__init__(self, *args, **kwargs)
def end_page(self, i):
from collections import defaultdict
lines = defaultdict(lambda : {})
for child in self.cur_item._objs: #<-- changed
if isinstance(child, LTChar):
(_,_,x,y) = child.bbox
line = lines[int(-y)]
line[x] = child._text.encode(self.codec) #<-- changed
for y in sorted(lines.keys()):
line = lines[y]
self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
self.outfp.write("\n")
# ... the following part of the code is a remix of the
# convert() function in the pdfminer/tools/pdf2text module
rsrc = PDFResourceManager()
outfp = StringIO()
device = CsvConverter(rsrc, outfp, codec="utf-8", laparams=LAParams())
# becuase my test documents are utf-8 (note: utf-8 is the default codec)
doc = PDFDocument()
fp = open(filename, 'rb')
parser = PDFParser(fp)
parser.set_document(doc)
doc.set_parser(parser)
doc.initialize('')
interpreter = PDFPageInterpreter(rsrc, device)
for i, page in enumerate(doc.get_pages()):
outfp.write("START PAGE %d\n" % i)
if page is not None:
interpreter.process_page(page)
outfp.write("END PAGE %d\n" % i)
device.close()
fp.close()
return outfp.getvalue()
LTTextItem
в LTChar
. unixuser.org/~euske/python/pdfminer/index.html#changes
20110515
на ваш коментар.
Оскільки жодне з цих рішень не підтримує останню версію PDFMiner, я написав просте рішення, яке поверне текст pdf за допомогою PDFMiner. Це допоможе тим, хто отримує помилки при імпортіprocess_pdf
import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
from cStringIO import StringIO
def pdfparser(data):
fp = file(data, 'rb')
rsrcmgr = PDFResourceManager()
retstr = StringIO()
codec = 'utf-8'
laparams = LAParams()
device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
# Create a PDF interpreter object.
interpreter = PDFPageInterpreter(rsrcmgr, device)
# Process each page contained in the document.
for page in PDFPage.get_pages(fp):
interpreter.process_page(page)
data = retstr.getvalue()
print data
if __name__ == '__main__':
pdfparser(sys.argv[1])
Дивіться нижче код, який працює для Python 3:
import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
import io
def pdfparser(data):
fp = open(data, 'rb')
rsrcmgr = PDFResourceManager()
retstr = io.StringIO()
codec = 'utf-8'
laparams = LAParams()
device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
# Create a PDF interpreter object.
interpreter = PDFPageInterpreter(rsrcmgr, device)
# Process each page contained in the document.
for page in PDFPage.get_pages(fp):
interpreter.process_page(page)
data = retstr.getvalue()
print(data)
if __name__ == '__main__':
pdfparser(sys.argv[1])
python3
, крім очевидних дужок після print
команди, потрібно замінити file
команду на open
та імпортувати StringIO
з пакетаio
Pdftotext Програма з відкритим кодом (частина Xpdf), яку ви можете викликати з python (не те, що ви просили, але може бути корисним). Я користувався ним без проблем. Я думаю, що Google використовує його на робочому столі Google.
-layout
можливістю зберігати текст у тому самому положенні, що і в PDF. Тепер якби я лише міг зрозуміти, як передати вміст PDF у нього.
pdftotext
Здається, працює дуже добре, але йому потрібен другий аргумент - це дефіс, якщо ви хочете побачити результати на stdout.
find . -iname "*.pdf" -exec pdftotext -enc UTF-8 -eol unix -raw {} \;
За замовчуванням згенеровані файли приймають оригінальне ім'я з .txt
розширенням.
pyPDF працює чудово (якщо припустити, що ви працюєте з добре сформованими PDF-файлами). Якщо все, що вам потрібно, це текст (з пробілами), ви можете просто зробити:
import pyPdf
pdf = pyPdf.PdfFileReader(open(filename, "rb"))
for page in pdf.pages:
print page.extractText()
Ви також можете легко отримати доступ до метаданих, даних зображень тощо.
Коментар до коду extraText зазначає:
Знайдіть усі команди малювання тексту у порядку, який вони надаються у потоці вмісту, та витягніть текст. Це добре працює для деяких PDF-файлів, але погано для інших, залежно від використовуваного генератора. Це буде вдосконалено в майбутньому. Не покладайтеся на порядок виходу тексту з цієї функції, оскільки він зміниться, якщо цю функцію зробити більш досконалою.
Невже це проблема чи ні, залежить від того, що ви робите з текстом (наприклад, якщо замовлення не має значення, це добре, або якщо генератор додає текст у потік у порядку, коли він буде відображатися, це добре) . Я маю код вилучення pyPdf у щоденному використанні, без проблем.
Ви також можете досить легко використовувати pdfminer як бібліотеку. Ви маєте доступ до вмістової моделі pdf і можете створити власне вилучення тексту. Я зробив це, щоб перетворити вміст PDF у текст, розділений крапкою з комою, використовуючи наведений нижче код.
Функція просто сортує об'єкти вмісту TextItem відповідно до їх координат y та x та виводить елементи з тією ж координатою y, що і один текстовий рядок, відокремлюючи об'єкти в одному рядку з ';' символів.
Використовуючи цей підхід, я зміг витягнути текст із PDF, з якого жоден інший інструмент не зміг витягти вміст, придатний для подальшого розбору. Інші інструменти, які я спробував, включають pdftotext, ps2ascii та онлайн-інструмент pdftextonline.com.
pdfminer - це безцінний інструмент для скреблінгу PDF-файлів.
def pdf_to_csv(filename):
from pdflib.page import TextItem, TextConverter
from pdflib.pdfparser import PDFDocument, PDFParser
from pdflib.pdfinterp import PDFResourceManager, PDFPageInterpreter
class CsvConverter(TextConverter):
def __init__(self, *args, **kwargs):
TextConverter.__init__(self, *args, **kwargs)
def end_page(self, i):
from collections import defaultdict
lines = defaultdict(lambda : {})
for child in self.cur_item.objs:
if isinstance(child, TextItem):
(_,_,x,y) = child.bbox
line = lines[int(-y)]
line[x] = child.text
for y in sorted(lines.keys()):
line = lines[y]
self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
self.outfp.write("\n")
# ... the following part of the code is a remix of the
# convert() function in the pdfminer/tools/pdf2text module
rsrc = PDFResourceManager()
outfp = StringIO()
device = CsvConverter(rsrc, outfp, "ascii")
doc = PDFDocument()
fp = open(filename, 'rb')
parser = PDFParser(doc, fp)
doc.initialize('')
interpreter = PDFPageInterpreter(rsrc, device)
for i, page in enumerate(doc.get_pages()):
outfp.write("START PAGE %d\n" % i)
interpreter.process_page(page)
outfp.write("END PAGE %d\n" % i)
device.close()
fp.close()
return outfp.getvalue()
ОНОВЛЕННЯ :
Код вище написаний проти старої версії API, дивіться мій коментар нижче.
pdfminer
, ні pdflib
). Я пропоную вам ознайомитись з джерелом pdf2txt.py
у джерелі PDFminer. Код, наведений вище, був натхненний старою версією цього файлу.
slate
це проект, який дозволяє дуже просто використовувати PDFMiner з бібліотеки:
>>> with open('example.pdf') as f:
... doc = slate.PDF(f)
...
>>> doc
[..., ..., ...]
>>> doc[1]
'Text from page 2...'
Мені потрібно було перетворити певний PDF у звичайний текст у модулі python. Я використав PDFMiner 20110515, прочитавши їхній інструмент pdf2txt.py , я написав цей простий фрагмент:
from cStringIO import StringIO
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
def to_txt(pdf_path):
input_ = file(pdf_path, 'rb')
output = StringIO()
manager = PDFResourceManager()
converter = TextConverter(manager, output, laparams=LAParams())
process_pdf(manager, converter, input_)
return output.getvalue()
C:\Python27\Scripts\pdfminer\tools\pdf2txt.py
Перестановка коду pdf2txt.py, який постачається з pdfminer; ви можете зробити функцію, яка пройде шлях до pdf; необов'язково, зовнішній вигляд (txt | html | xml | тег) і вибирає, як командний рядок pdf2txt {'-o': '/path/to/outfile.txt' ...}. За замовчуванням ви можете зателефонувати:
convert_pdf(path)
Буде створено текстовий файл, побратим файлової системи до оригінального PDF.
def convert_pdf(path, outtype='txt', opts={}):
import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter, process_pdf
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter, TagExtractor
from pdfminer.layout import LAParams
from pdfminer.pdfparser import PDFDocument, PDFParser
from pdfminer.pdfdevice import PDFDevice
from pdfminer.cmapdb import CMapDB
outfile = path[:-3] + outtype
outdir = '/'.join(path.split('/')[:-1])
debug = 0
# input option
password = ''
pagenos = set()
maxpages = 0
# output option
codec = 'utf-8'
pageno = 1
scale = 1
showpageno = True
laparams = LAParams()
for (k, v) in opts:
if k == '-d': debug += 1
elif k == '-p': pagenos.update( int(x)-1 for x in v.split(',') )
elif k == '-m': maxpages = int(v)
elif k == '-P': password = v
elif k == '-o': outfile = v
elif k == '-n': laparams = None
elif k == '-A': laparams.all_texts = True
elif k == '-D': laparams.writing_mode = v
elif k == '-M': laparams.char_margin = float(v)
elif k == '-L': laparams.line_margin = float(v)
elif k == '-W': laparams.word_margin = float(v)
elif k == '-O': outdir = v
elif k == '-t': outtype = v
elif k == '-c': codec = v
elif k == '-s': scale = float(v)
#
CMapDB.debug = debug
PDFResourceManager.debug = debug
PDFDocument.debug = debug
PDFParser.debug = debug
PDFPageInterpreter.debug = debug
PDFDevice.debug = debug
#
rsrcmgr = PDFResourceManager()
if not outtype:
outtype = 'txt'
if outfile:
if outfile.endswith('.htm') or outfile.endswith('.html'):
outtype = 'html'
elif outfile.endswith('.xml'):
outtype = 'xml'
elif outfile.endswith('.tag'):
outtype = 'tag'
if outfile:
outfp = file(outfile, 'w')
else:
outfp = sys.stdout
if outtype == 'txt':
device = TextConverter(rsrcmgr, outfp, codec=codec, laparams=laparams)
elif outtype == 'xml':
device = XMLConverter(rsrcmgr, outfp, codec=codec, laparams=laparams, outdir=outdir)
elif outtype == 'html':
device = HTMLConverter(rsrcmgr, outfp, codec=codec, scale=scale, laparams=laparams, outdir=outdir)
elif outtype == 'tag':
device = TagExtractor(rsrcmgr, outfp, codec=codec)
else:
return usage()
fp = file(path, 'rb')
process_pdf(rsrcmgr, device, fp, pagenos, maxpages=maxpages, password=password)
fp.close()
device.close()
outfp.close()
return
PDFminer дав мені, можливо, один рядок [стор. 1 з 7 ...] на кожній сторінці pdf-файлу, який я спробував з ним.
Найкраща відповідь, яку я маю поки що, - це pdftoipe, або код c ++, заснований на Xpdf.
дивіться моє запитання про те, як виглядає вихід pdftoipe.
Крім того, існує PDFTextStream , комерційна бібліотека Java, яка також може використовуватися з Python.
Я використав pdftohtml
з -xml
аргументом, прочитайте результат з subprocess.Popen()
, який дасть вам x координату, y координату, ширину, висоту та шрифт кожного фрагмента тексту в PDF. Я думаю, що саме це, напевно, використовує і «evince», оскільки випливають ті самі повідомлення про помилки.
Якщо вам потрібно обробити стовпчикові дані, це стає дещо складніше, оскільки вам доведеться винайти алгоритм, який відповідає вашому pdf-файлу. Проблема полягає в тому, що програми, що створюють PDF-файли, насправді не обов'язково викладають текст у будь-якому логічному форматі. Ви можете спробувати прості алгоритми сортування, і це іноді працює, але можуть бути маленькі «хитрі» та «бродячі» фрагменти тексту, які не впорядковуються в тому порядку, як ви думали, що вони будуть. Тож треба проявляти творчість.
Знадобилося мені близько 5 годин, щоб розібратися з файлом у форматі PDF, над яким я працював. Але це працює досить добре зараз. Удачі.
Знайшли таке рішення сьогодні. Для мене чудово працює. Навіть візуалізація сторінок PDF на зображення PNG. http://www.swftools.org/gfx_tutorial.html