PDFminer: извлекать текст с информацией о шрифте
Я нахожу этот вопрос, но он использует командную строку, и я не хочу вызывать скрипт Python в командной строке, используя подпроцесс и анализировать HTML-файлы, чтобы получить информацию о шрифте.
Я хочу использовать PDFminer в качестве библиотеки, и я нахожу этот вопрос, но они просто предназначены для извлечения простых текстов, без другой информации, такой как имя шрифта, размер шрифта и так далее.
7 ответов
#!/usr/bin/env python
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.layout import LAParams
from pdfminer.converter import PDFPageAggregator
import pdfminer
def createPDFDoc(fpath):
fp = open(fpath, 'rb')
parser = PDFParser(fp)
document = PDFDocument(parser, password='')
# Check if the document allows text extraction. If not, abort.
if not document.is_extractable:
raise "Not extractable"
else:
return document
def createDeviceInterpreter():
rsrcmgr = PDFResourceManager()
laparams = LAParams()
device = PDFPageAggregator(rsrcmgr, laparams=laparams)
interpreter = PDFPageInterpreter(rsrcmgr, device)
return device, interpreter
def parse_obj(objs):
for obj in objs:
if isinstance(obj, pdfminer.layout.LTTextBox):
for o in obj._objs:
if isinstance(o,pdfminer.layout.LTTextLine):
text=o.get_text()
if text.strip():
for c in o._objs:
if isinstance(c, pdfminer.layout.LTChar):
print "fontname %s"%c.fontname
# if it's a container, recurse
elif isinstance(obj, pdfminer.layout.LTFigure):
parse_obj(obj._objs)
else:
pass
document=createPDFDoc("/tmp/simple.pdf")
device,interpreter=createDeviceInterpreter()
pages=PDFPage.create_pages(document)
interpreter.process_page(pages.next())
layout = device.get_result()
parse_obj(layout._objs)
Полное раскрытие, я являюсь одним из сопровождающих pdfminer.six . Это поддерживаемая сообществом версия pdfminer для Python 3.
В настоящее время pdfminer.six имеет несколько API для извлечения текста и информации из PDF. Для программного извлечения информации я бы посоветовал использовать
extract_pages()
. Это позволяет вам проверять все элементы на странице, упорядоченные в осмысленной иерархии, созданной алгоритмом макета.
Следующий пример представляет собой питонический способ отображения всех элементов в иерархии. Он использует файл simple1.pdf из каталога примеров файла pdfminer.six.
from pathlib import Path
from typing import Iterable, Any
from pdfminer.high_level import extract_pages
def show_ltitem_hierarchy(o: Any, depth=0):
"""Show location and text of LTItem and all its descendants"""
if depth == 0:
print('element fontname text')
print('------------------------------ -------------------- -----')
print(
f'{get_indented_name(o, depth):<30.30s} '
f'{get_optional_fontinfo(o):<20.20s} '
f'{get_optional_text(o)}'
)
if isinstance(o, Iterable):
for i in o:
show_ltitem_hierarchy(i, depth=depth + 1)
def get_indented_name(o: Any, depth: int) -> str:
"""Indented name of class"""
return ' ' * depth + o.__class__.__name__
def get_optional_fontinfo(o: Any) -> str:
"""Font info of LTChar if available, otherwise empty string"""
if hasattr(o, 'fontname') and hasattr(o, 'size'):
return f'{o.fontname} {round(o.size)}pt'
return ''
def get_optional_text(o: Any) -> str:
"""Text of LTItem if available, otherwise empty string"""
if hasattr(o, 'get_text'):
return o.get_text().strip()
return ''
path = Path('~/Downloads/simple1.pdf').expanduser()
pages = extract_pages(path)
show_ltitem_hierarchy(pages)
На выходе отображаются различные элементы в иерархии, имя и размер шрифта, если они доступны, а также текст, который содержит этот элемент.
element fontname text
------------------------------ -------------------- -----
generator
LTPage
LTTextBoxHorizontal Hello
LTTextLineHorizontal Hello
LTChar Helvetica 24pt H
LTChar Helvetica 24pt e
LTChar Helvetica 24pt l
LTChar Helvetica 24pt l
LTChar Helvetica 24pt o
LTChar Helvetica 24pt
LTAnno
LTTextBoxHorizontal World
LTTextLineHorizontal World
LTChar Helvetica 24pt W
LTChar Helvetica 24pt o
LTChar Helvetica 24pt r
LTChar Helvetica 24pt l
LTChar Helvetica 24pt d
LTAnno
LTTextBoxHorizontal Hello
LTTextLineHorizontal Hello
LTChar Helvetica 24pt H
LTChar Helvetica 24pt e
LTChar Helvetica 24pt l
LTChar Helvetica 24pt l
LTChar Helvetica 24pt o
LTChar Helvetica 24pt
LTAnno
LTTextBoxHorizontal World
LTTextLineHorizontal World
LTChar Helvetica 24pt W
LTChar Helvetica 24pt o
LTChar Helvetica 24pt r
LTChar Helvetica 24pt l
LTChar Helvetica 24pt d
LTAnno
LTTextBoxHorizontal H e l l o
LTTextLineHorizontal H e l l o
LTChar Helvetica 24pt H
LTAnno
LTChar Helvetica 24pt e
LTAnno
LTChar Helvetica 24pt l
LTAnno
LTChar Helvetica 24pt l
LTAnno
LTChar Helvetica 24pt o
LTAnno
LTChar Helvetica 24pt
LTAnno
LTTextBoxHorizontal W o r l d
LTTextLineHorizontal W o r l d
LTChar Helvetica 24pt W
LTAnno
LTChar Helvetica 24pt o
LTAnno
LTChar Helvetica 24pt r
LTAnno
LTChar Helvetica 24pt l
LTAnno
LTChar Helvetica 24pt d
LTAnno
LTTextBoxHorizontal H e l l o
LTTextLineHorizontal H e l l o
LTChar Helvetica 24pt H
LTAnno
LTChar Helvetica 24pt e
LTAnno
LTChar Helvetica 24pt l
LTAnno
LTChar Helvetica 24pt l
LTAnno
LTChar Helvetica 24pt o
LTAnno
LTChar Helvetica 24pt
LTAnno
LTTextBoxHorizontal W o r l d
LTTextLineHorizontal W o r l d
LTChar Helvetica 24pt W
LTAnno
LTChar Helvetica 24pt o
LTAnno
LTChar Helvetica 24pt r
LTAnno
LTChar Helvetica 24pt l
LTAnno
LTChar Helvetica 24pt d
LTAnno
(Аналогичный ответ здесь , здесь и здесь , я постараюсь синхронизировать их.)
Этот подход не использует PDFMiner, но делает свое дело.
Сначала преобразуйте документ PDF в docx. Используя python-docx, вы можете получить информацию о шрифте. Вот пример получения всего жирного текста
from docx import *
document = Document('/path/to/file.docx')
for para in document.paragraphs:
for run in para.runs:
if run.bold:
print run.text
Если вы действительно хотите использовать PDFMiner, вы можете попробовать это. Передача '-t' конвертирует PDF в HTML со всей информацией о шрифте.
Надеюсь, это может вам помочь:)
Получите семейство шрифтов:
if isinstance(c, pdfminer.layout.LTChar):
print (c.fontname)
Получите размер шрифта:
if isinstance(c, pdfminer.layout.LTChar):
print (c.size)
Получите font-positon:
if isinstance(c, pdfminer.layout.LTChar):
print (c.bbox)
Получите информацию об изображении:
if isinstance(obj, pdfminer.layout.LTImage):
outputImg = "<Image>\n"
outputImg += ("name: %s, " % obj.name)
outputImg += ("x: %f, " % obj.bbox[0])
outputImg += ("y: %f\n" % obj.bbox[1])
outputImg += ("width1: %f, " % obj.width)
outputImg += ("height1: %f, " % obj.height)
outputImg += ("width2: %f, " % obj.stream.attrs['Width'])
outputImg += ("height2: %f\n" % obj.stream.attrs['Height'])
print (outputImg)
Если вы хотите получить размер шрифта или имя шрифта из файла PDF с помощью библиотеки PDF-майнера, вам необходимо интерпретировать всю страницу pdf. Вы должны решить, для какого слова, фразы вы хотите получить размер шрифта и название шрифта (так как на странице может быть несколько слов с разными размерами шрифта). Структура с использованием PDF-майнера для страницы: PDFPageInterpreter -> LTTextBox -> LTChar. Как только вы узнали, для какого слова вы хотите получить размер шрифта, вы вызываете: метод size для размера шрифта (который на самом деле является высотой) и имя шрифта для шрифта. Код должен выглядеть так: вы передаете путь к файлу pdf, слово, для которого хотите получить размер шрифта и номер страницы (на какой странице ищется слово):
def get_fontsize_and_fontname_for_word(self, pdf_path, word, page_number):
resource_manager = PDFResourceManager()
layout_params = LAParams()
device = PDFPageAggregator(resource_manager, laparams=layout_params)
pdf_file = file(pdf_path, 'rb')
pdf_page_interpreter = PDFPageInterpreter(resource_manager, device)
global actual_font_size_pt, actual_font_name
for current_page_number, page in enumerate(PDFPage.get_pages(pdf_file)):
if current_page_number == int(page_number) - 1:
pdf_page_interpreter.process_page(page)
layout = device.get_result()
for textbox_element in layout:
if isinstance(textbox_element, LTTextBox):
for line in textbox_element:
word_from_textbox = line.get_text().strip()
if word in word_from_textbox:
for char in line:
if isinstance(char, LTChar):
# convert pixels to points
actual_font_size_pt = int(char.size) * 72 / 96
# remove prefixed font name, such as QTBAAA+
actual_font_name = char.fontname[7:]
pdf_file.close()
device.close()
return actual_font_size_pt, actual_font_name
Вы можете проверить, какие еще свойства поддерживает класс LTChar.
Взгляните на PDFlib, он может извлекать информацию о шрифтах по вашему желанию и имеет библиотеку Python, которую вы можете импортировать в свои скрипты и работать с ней.
Некоторая информация находится на более низком уровне в классе LTChar. Это кажется логичным, потому что размер шрифта, курсив, полужирный шрифт и т. Д. Можно применить к одному символу.
Больше информации здесь: https://github.com/euske/pdfminer/blob/master/pdfminer/layout.py
Но я все еще не понимаю, как цвет шрифта не в этом классе