Сообщить об ошибке.

Модуль mammoth в Python, конвертер .docx в HTML

Преобразование документов .docx в легкий HTML

Модуль mammoth предназначен для преобразования документов .docx, например, созданных в Microsoft Word, Google Docs и LibreOffice в HTML. Этот модуль стремится создавать простой и чистый HTML, используя семантическую информацию в документе и игнорируя другие детали. Например, mammoth преобразует любой абзац со стилем Heading 1 в элементы <h1> и не пытается точно скопировать стиль (шрифт, размер текста, цвет и т. д.) заголовка.

Существует большое несоответствие между структурой, используемой в .docx, и структурой HTML, а это означает, что преобразование вряд ли будет идеальным для более сложных документов. Модуль mammoth работает лучше всего, если в документе Microsoft Word, стили используются только для семантической разметки.

В настоящее время поддерживаются следующая разметка .docx:

  • Заголовки.
  • Списки.
  • Настраиваемое отображение из собственных стилей .docx в HTML. Например, можно преобразовать заголовок WarningHeading в h1.warning, предоставив соответствующее сопоставление стилей.
  • Таблицы. Форматирование самой таблицы, такое как границы, в настоящее время игнорируется, но форматирование текста обрабатывается так же, как и в остальной части документа.
  • Сноски и концевые примечания.
  • Изображения.
  • Жирный шрифт, курсив, подчеркивание, зачеркивание, верхний и подстрочный индексы.
  • Связи.
  • Разрывы строк.
  • Текстовые поля. Содержимое текстового поля обрабатывается как отдельный абзац, который появляется после абзаца, содержащего текстовое поле.
  • Комментарии.

Установка модуля mammoth в виртуальное окружение:

# создаем виртуальное окружение 
$ python3 -m venv .venv --prompt VirtualEnv
# активируем виртуальное окружение 
$ source .venv/bin/activate
# ставим модуль mammoth
(VirtualEnv) :~$ python3 -m pip install mammoth --upgrade

Содержание:

Преобразование DOCX в HTML в командной строке.

Чтобы преобразовать DOCX-файлы в HTML, используя командную строку, необходимо команде mammoth передать путь к файлу с расширением .docx и указать выходной файл. Например:

$ mammoth document.docx output.html

Если выходной файл не указан, то выходные данные записываются в стандартный вывод сонсоли.

Результатом является HTML-фрагмент в кодировке UTF-8, а не полный HTML-документ. Так как кодировка явно не задана в HTML-фрагменте, то открытие выходного файла в веб-браузере может привести к неправильному отображению символов Unicode, если браузер по умолчанию не использует UTF-8.

Извлечение изображений из документа DOCX.

По умолчанию изображения включаются в выходной HTML-код. Если указан выходной каталог параметром --output-dir, то изображения записываются в указанную папку в отдельные файлы (очень удобно для извлечения изображений из документа DOCX). Например:

$ mammoth document.docx --output-dir=img-dir

Существующие файлы будут перезаписаны, если они есть.

Встраивание стилей в итоговый HTML-фрагмент.

Пользовательскую карту стилей можно прочитать из файла с помощью параметра --style-map. Например:

$ mammoth document.docx output.html --style-map=custom-style-map.txt

Где custom-style-map.txt - текстовый файл с описанием пользовательских стилей выглядит примерно так:

p[style-name='Aside Heading'] => div.aside > h2:fresh
p[style-name='Aside Text'] => div.aside > p:fresh

Описание синтаксиса для составления карт стилей можно посмотреть в разделе "Написание пользовательских карт стилей".

Преобразование DOCX в HTML в коде Python.

Чтобы преобразовать существующий файл .docx в HTML, необходимо передать файлоподобный объект в функцию mammoth.convert_to_html(). Файл должен быть открыт в бинарном режиме. Например:

import mammoth

with open("document.docx", "rb") as docx_file:
    result = mammoth.convert_to_html(docx_file)
    # сгенерированный HTML
    html = result.value
    # предупреждения во время конвертации
    messages = result.messages

Также можно извлечь необработанный текст документа с помощью функции mammoth.extract_raw_text(). Эта функция игнорирует все форматирование в документе. За каждым абзацем следует две новые строки.

with open("document.docx", "rb") as docx_file:
    result = mammoth.extract_raw_text(docx_file)
    # Необработанный текст
    text = result.value 
    # предупреждения во время конвертации
    messages = result.messages # Any messages

Функция mammoth.convert_to_html(fileobj, **kwargs):

Функция mammoth.convert_to_html() преобразует исходный документ DOCX в HTML.

Принимаемые аргументы:

  • fileobj: файлоподобный объект, содержащий исходный документ. Файлы должны открываться в двоичном режиме.
  • style_map: строка, задающая отображение стилей Word в HTML. Описание синтаксиса приведено в разделе "Написание пользовательских карт стилей".
  • include_embedded_style_map: по умолчанию, если документ содержит встроенную карту стилей, то она объединяется с картой стилей по умолчанию. Чтобы игнорировать любые встроенные карты стилей, передайте include_embedded_style_map=False.
  • include_default_style_map: по умолчанию карта стилей, переданная в style_map, объединяется с картой стилей по умолчанию. Чтобы полностью отказаться от использования карты стилей по умолчанию, передайте include_default_style_map=False.
  • convert_image: по умолчанию изображения преобразуются в элементы <img> с указанием источника, встроенного в атрибут src. Установите этот аргумент в значение конвертера изображений, чтобы переопределить поведение по умолчанию.
  • ignore_empty_paragraphs: по умолчанию пустые абзацы игнорируются. Установите для этого параметра значение False, чтобы сохранить пустые абзацы в выходных данных.
  • id_prefix: строка, добавляемая к любым сгенерированным идентификаторам, таким как те, которые используются закладками, сносками и концевыми примечаниями. По умолчанию используется пустая строка.

Возвращает результат со следующими свойствами:

  • value: сгенерированный HTML;
  • messages: любые сообщения, такие как ошибки и предупреждения, сгенерированные во время преобразования.

Каждое сообщение messages имеет следующие свойства:

  • type: строка, представляющая тип сообщения, например "warning".
  • messages: строка, содержащая фактическое сообщение.

Пользовательский обработчик стилей в выходном HTML.

По умолчанию модуль mammoth сопоставляет некоторые общие стили .docx с элементами HTML. Например, абзац с названием стиля Heading 1 преобразуется в элемент <h1>. Можно передать пользовательскую карту стилей, в качестве второго аргумента style_map функции mammoth.convert_to_html(). Допустим, что необходимо преобразовать абзацы с названием стиля Section Title в элементы <h1>, а абзацы с названием стиля Subsection Title в элементы <h2>:

import mammoth

style_map = """
p[style-name='Section Title'] => h1:fresh
p[style-name='Subsection Title'] => h2:fresh
"""

with open("document.docx", "rb") as docx_file:
    html = mammoth.convert_to_html(docx_file, style_map=style_map)

Пользовательские сопоставления style_map будут использоваться вместо сопоставлений стилей по умолчанию. Чтобы вообще отказаться от сопоставления стилей по умолчанию, передайте третий ключевой аргумент include_default_style_map=False:

html = mammoth.convert_to_html(docx_file, style_map=style_map, include_default_style_map=False)

Описание синтаксиса для составления карт стилей можно посмотреть в разделе "Написание пользовательских карт стилей".

Функция mammoth.embed_style_map(fileobj, style_map):

Функция mammoth.embed_style_map() встраивает карту стилей style_map в файл fileobj. Когда mammoth читает файловый объект, он будет использовать встроенную карту стилей (т.е. дополнительно передавать ее аргументом style_map в функцию mammoth.convert_to_html уже будет не надо).

Принимаемые аргументы:

  • fileobj: файлоподобный объект, содержащий исходный документ. Файлы должны быть открыты для чтения и записи в двоичном режиме.
  • style_map: карта стилей для встраивания.

Возвращает None.

Изменение стилей документа Bold, Italic, Underline и т.д. в выходном HTML.

Полужирный текст.

По умолчанию полужирный текст заключен в теги <strong>. Это поведение можно изменить, добавив отображение стиля для b. Например, чтобы заключить полужирный текст в теги <em>:

style_map = "b => em"

with open("document.docx", "rb") as docx_file:
    result = mammoth.convert_to_html(docx_file, style_map=style_map)

Текст, выделенный курсивом.

По умолчанию текст, выделенный курсивом, заключен в теги <em>. Это поведение можно изменить, добавив сопоставление стилей для i. Например, чтобы поместить текст, выделенный курсивом, в теги <strong>:

style_map = "i => strong"

with open("document.docx", "rb") as docx_file:
    result = mammoth.convert_to_html(docx_file, style_map=style_map)

Подчеркивание текста.

По умолчанию подчеркивание любого текста игнорируется, поскольку подчеркивание можно спутать со ссылками в HTML-документах. Это поведение можно изменить, добавив сопоставление стилей для u. Например, предположим, что в исходном документе для выделения используется подчеркивание. Код ниже любой явно подчеркнутый исходный текст заключает в теги <em>:

style_map = "u => em"

with open("document.docx", "rb") as docx_file:
    result = mammoth.convert_to_html(docx_file, style_map=style_map)

Зачеркнутый текст.

По умолчанию зачеркнутый текст заключен в теги <s>. Это поведение можно изменить, добавив сопоставление стилей для strike. Например, чтобы обернуть зачеркнутый текст в теги <del>:

style_map = "strike => del"

with open("document.docx", "rb") as docx_file:
    result = mammoth.convert_to_html(docx_file, style_map=style_map)

Комментарии в тексте.

По умолчанию комментарии игнорируются. Чтобы включить комментарии в сгенерированный HTML-код, добавьте сопоставление стилей для comment-reference. Например:

style_map = "comment-reference => sup"

with open("document.docx", "rb") as docx_file:
    result = mammoth.convert_to_html(docx_file, style_map=style_map)

Комментарии будут добавлены в конец документа со ссылками на комментарии, обернутыми с использованием указанного сопоставления стилей.

Пользовательские обработчики изображений.

По умолчанию изображения преобразуются в элементы <img> с включенным источником в атрибут src. Это поведение можно изменить, задав для аргумента convert_image значение конвертера изображений.

Например, следующий код будет воспроизводить поведение по умолчанию:

def convert_image(image):
    with image.open() as image_bytes:
        encoded_src = base64.b64encode(image_bytes.read()).decode("ascii")
    return {
        "src": f"data:{image.content_type};base64,{encoded_src}"
    }

with open("document.docx", "rb") as docx_file:
    mammoth.convert_to_html(docx_file, convert_image=mammoth.images.img_element(convert_image))

Конвертер изображений по умолчанию mammoth.images.data_uri.

Конвертер изображений можно создать, вызвав mammoth.images.img_element(func). Это создаст элемент <img> для каждого изображения в исходном .docx файле. Аргумент func должен быть функцией, принимающей один аргумент image. Этот аргумент является преобразуемым элементом изображения и обладает следующими свойствами:

  • open(): открывает файл изображения. Возвращает файлоподобный объект.
  • content_type: возвращает тип содержимого изображения, например image/png.

Функция func должна возвращать список атрибутов для элемента <img>. Как минимум, это должно включать атрибут src. Если для изображения будет найден какой-либо альтернативный текст, он будет автоматически добавлен к атрибутам элемента.

Обратите внимание, что изображения WMF по умолчанию не обрабатываются модулем mammoth.

Написание пользовательских карт стилей.

Карта стилей состоит из сопоставлений стилей, каждая из которых начинается с новой строки. Пустые строки и строки, начинающиеся с #, игнорируются.

Отображение стиля состоит из двух частей:

  • Слева перед стрелкой находится средство сопоставления элементов документа.
  • Справа, после стрелки, HTML-тег.

При преобразовании каждого абзаца mammoth находит первое сопоставление стилей, в котором средство сопоставления элементов документа соответствует текущему абзацу. Затем mammoth гарантирует, что HTML-тег будет удовлетворен.

Понятие "свежести" HTML-элемента.

При написании сопоставлений стилей полезно понимать "свежесть" HTML-элемента. При генерации HTML mammoth закроет HTML-тег только при необходимости. В противном случае элемент используются повторно.

Например, предположим, что одним из указанных сопоставлений стилей является p[style-name='Heading 1'] => h1. Если mammoth встречает абзац в .docx с названием стиля Heading 1, то абзац .docx преобразуется в элемент <h1> с тем же текстом. Если следующий абзац в .docx также имеет название стиля Heading 1, то текст этого абзаца будет добавлен к существующему тегу <h1>, и не приведет к созданию нового HTML-элемента <h1>.

В большинстве случаев, необходимо будет сгенерировать новый элемент h1. Это можно сделать с помощью модификатора :fresh:

p[style-name='Heading 1'] => h1:fresh

Два последовательных абзаца с Heading 1 будут преобразованы в два отдельных элемента h1.

Повторное использование элементов полезно при создании более сложных HTML-структур. Например, предположим, что файл .docx содержит отступы aside. У каждого отступа aside может быть заголовок и некоторый основной текст, которые должны содержаться в пределах одного элемента div.aside. В этом случае могут быть полезны сопоставления стилей, подобные:

p[style-name='Aside Heading'] => div.aside > h2:fresh 
# и 
p[style-name='Aside Text'] => div.aside > p:fresh

Совпадения с абзацем, прогоном и таблицей.

  • p => - совпадение с любым абзацем;
  • r => - совпадение с любым прогоном;
  • table => - совпадение с любой таблицей;

Использование в карте стилей:

# обернет абзац в <div>...</div>
p => div
# обернет абзац в <p>...</p>
p => p 
# обернет прогон в <span>...</span>
r => span

Чтобы сопоставить абзац, прогон или таблицу с определенным стилем документа DOCX, можно сослаться на стиль по имени. Это название стиля, которое отображается в Microsoft Word или LibreOffice. Например, чтобы сопоставить абзац с названием стиля Heading 1:

p[style-name='Heading 1'] => h1

Можно также сопоставить имя стиля по префиксу. Например, чтобы соответствовать абзацу, имя стиля которого начинается с Heading:

p[style-name^='Heading'] => h1

На стили также можно ссылаться по идентификатору стиля. Это идентификатор, используемый внутри файла .docx. Чтобы сопоставить абзац или текст с определенным идентификатором стиля, нужно добавить точку, за которой следует идентификатор стиля. Например, чтобы сопоставить абзац с идентификатором стиля Heading1:

p.Heading1 => h1

Совпадения с Bold, Italic, Underline и т.д.

Обратите внимание, что нижеперечисленные индификаторы соответствуют только тексту, к которому явно применен жирный (курсив, подчеркнутый и т.д.) шрифт. Он не будет соответствовать тексту, который помещен в абзац или прогон со стилем - жирный (курсив, подчеркнутый и т.д.).

  • b => - соответствует явно выделенному жирным шрифтом тексту;
  • i => - соответствует явно выделенному курсивом тексту;
  • u => - соответствует c явно подчеркнутым текстом;
  • strike => - соответствует с явно зачеркнутым текстом;
  • all-caps => - соответствует со всеми заглавными буквами текста;
  • small-caps => - соответствует с явно маленькими заглавными буквами;
  • p[style-name='Comment'] => ! - ! игнорирует элемент документа. Например, чтобы игнорировать любой абзац со стилем Comment.

Смотрите примеры использования модификаторов выше, в "Изменение стилей документа Bold, Italic, Underline и т.д. в выходном HTML"

HTML-теги и внедрение пользовательских CSS-классов.

Самый простой путь преобразовать совпадение - это указать один HTML-элемент. Например, чтобы указать элемент:

`p.Heading1 => h1`

Чтобы присвоить элементу класс CSS, необходимо добавить точку, за которой следует название класса:

p.Heading1 => h1.section-title

Модификаторы должны использоваться в правильном порядке:

p[style-name^='Heading'] => h1.section-title:fresh

Чтобы указать разделитель для размещения между содержимым абзацев, которые свернуты вместе, необходимо использовать :separator('SEPARATOR STRING').

Например, предположим, что документ содержит блок кода, где каждая строка кода представляет собой абзац со стилем Code Block. Можно написать сопоставление стилей для сопоставления таких абзацев с элементами <pre>:

p[style-name='Code Block'] => pre

Поскольку <pre> не помечен как :fresh, то последовательные элементы <pre> будут свернуты вместе. Однако это приводит к тому, что весь код находится в одной строке. Можно использовать :separator для вставки новой строки между каждой строкой кода:

p[style-name='Code Block'] => pre:separator('\n')

Вложенные HTML-элементы.

Для указания вложенных HTML элементов необходимо использовать >. Например, чтобы указать h2 внутри div.aside:

p[style-name^='Heading2'] => div.aside > h2

Можно вкладывать элементы на любую глубину.