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

Но я все еще не понимаю, как цвет шрифта не в этом классе

Другие вопросы по тегам