Поиск слов в word python

Обновлено: 07.07.2024

В этой задаче столкнулся с такой проблемой как отсутствие нормальных библиотек для Python для парсинга информации с файлов!

Так как файлы были разных форматов (.rtf, .doc, .docx, .xls, .xlsx, .pdf) и что бы открыть и прочитать информацию из них помощью Python нужно было найти подходящие библиотеки. В .pdf были сканы, и мы вопрос с ними уже решили (об этом я рассказывал в предыдущей статье). Для работы с форматами .xls, .xlsx есть отличная библиотека pandas, которая на ура справляется с поставленной целью и не только. Pandas это высокоуровневая Python библиотека для анализа данных. В экосистеме Python, pandas является лучшей и быстроразвивающейся библиотекой для обработки и анализа данных. Мне приходится пользоваться ею практически каждый день!

Осталось решить вопрос с .rtf, .doc, .docx.

Rich Text Format, RTF — это формат текста придуманный группой программистов из Microsoft и Adobe в 82 году.

Для работы с этим форматом использовал разные библиотеки в том числе pyth.

.doc — то же является текстовым форматом, но более лучшим чем предыдущий.

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

В связи с этим .rtf и .doc просто приходилось конвертировать в формат .docx (про него ниже) и также сделал просто .exe-шник с помощью Python который конвертирует эти форматы в .docx.

Начиная с 2007 появился новый формат на основе XML — docx.

И так, с форматами .xls, .docx, проблем никаких не возникло. С помощью необходимых библиотек (docx, pandas, tkinter) работа с файлами, вытаскивание информации, по ключевым словам, или фразам была реализована! Сделан графический интерфейс (графический пользовательский интерфейс (ГПИ) (англ. graphical user interface, GUI)) также скомпилирована в .exe и добавлена инструкция.

Я хотел бы найти в текстовом файле Word 2007 (.docx) текстовую строку, например, «некоторую специальную фразу», которую можно / можно найти в результате поиска в Word.

Есть ли способ из Python, чтобы увидеть текст? Меня не интересует форматирование - я просто хочу классифицировать документы как имеющие или не имеющие «какую-то особую фразу».

Точнее, документ .docx - это Zip-архив в формате OpenXML: сначала нужно его распаковать.
Я скачал образец (Google: поисковый запрос типа файла: docx ) и после разархивирования нашел несколько папок. Папка word содержит сам документ в файле document.xml .

Docx - это просто zip-архив с множеством файлов внутри. Может быть, вы можете посмотреть на содержимое этих файлов? Кроме этого вам, вероятно, придется найти библиотеку, которая понимает формат слова, чтобы вы могли отфильтровать вещи, которые вам не интересны.

Вторым вариантом будет взаимодействие со словом и поиск по нему.

Вы можете использовать docx2txt , чтобы получить текст внутри документа, чем искать в этом тексте.

Вы должны быть в состоянии использовать интерфейс MSWord ActiveX для извлечения текста для поиска (или, возможно, выполнить поиск). Я понятия не имею, как вы получаете доступ к ActiveX из Python, хотя.

OLE Automation, вероятно, будет самым простым. Вы должны рассмотреть форматирование, потому что текст может выглядеть следующим образом в XML:

Нет простого способа найти это с помощью простого сканирования текста.

Проблема с поиском внутри XML-файла документа Word заключается в том, что текст может быть разбит на элементы по любому символу. Он будет разделен, если форматирование будет другим, например, как в Hello World . Но его можно разделить в любой точке, и это допустимо в OOXML. Таким образом, вы в конечном итоге будете иметь дело с XML, даже если форматирование не меняется в середине фразы!

Конечно, вы можете загрузить его в дерево XML DOM (не уверен, что это будет в Python) и попросить получить текст только в виде строки, но вы можете получить множество других «тупиков» только потому, что спецификация OOXML существует 6000 страниц в длину и MS Word может написать много "вещей", которые вы не ожидаете. Таким образом, вы можете написать свою собственную библиотеку обработки документов.

Или вы можете попробовать использовать Aspose.Words .

В этом примере «Course Outline.docx» представляет собой документ Word 2007, который содержит слово «Windows» и не содержит фразу «случайная другая строка».

По сути, вы просто открываете файл docx (который является zip-архивом), используя zipfile и найдите содержимое в файле «document.xml» в папке «word». Если вы хотите быть более изощренным, вы можете проанализировать XML, но если вы просто ищете фразу (которая, как вы знаете, не будет тэгом), вы можете просто посмотреть в XML-файле строку.

После прочтения вашего поста выше, я сделал 100% нативный модуль Python docx для решения этой конкретной проблемы.

Файл docx - это, по сути, zip-файл с XML-файлом внутри.
XML содержит форматирование, но также содержит текст.

В своей работе мы часто анализируем большой объем данных. Давайте рассмотрим, как можно автоматизировать процесс анализа документов на примере библиотеки docx (способной обрабатывать документы в формате. docx).

А также расскажем другие возможности, которые предлагает Python: как отделить текст с нужным стилем форматирования? Как извлечь все изображения из документа?

Для установки библиотеки в командной строке необходимо ввести:

После успешной установки библиотеки, её нужно импортировать в Python. Обратите внимание, что несмотря на то, что для установки использовалось название python-docx, при импорте следует называть библиотеку docx:

Как правило, мы обращаемся к автоматизации, когда нам нужно извлечь нужную информацию не из одного, а сразу из многих документов. Чтобы иметь возможность обработать все документы, для начала нужно собрать список таких документов. Здесь сможет помочь библиотека os, с помощью которой можно рекурсивно обойти директории, в которых хранятся документы. Предположим, что все они находятся внутри директории, где расположен скрипт:

import os paths = [] folder = os.getcwd() for root, dirs, files in os.walk(folder): for file in files: if file.endswith('docx') and not file.startswith('

Мы прошли по всем директориям и занесли в список paths все файлы с расширением. docx. Файлы, начинавшиеся с тильды, игнорировались (эти временные файлы возникают лишь тогда, когда в Windows открыт какой-либо из документов). Теперь, когда у нас уже есть список всех документов, можно начинать с ними работать:

В блоке выше на каждом шаге цикла в переменную doc записывается экземпляр, представляющий собой весь документ. Мы можем посмотреть основные свойства такого документа:

properties = doc.core_properties print('Автор документа:', properties.author) print('Автор последней правки:', properties.last_modified_by) print('Дата создания документа:', properties.created) print('Дата последней правки:', properties.modified) print('Дата последней печати:', properties.last_printed) print('Количество сохранений:', properties.revision)

Из основных свойств можно получить автора документа, основные даты, количество сохранений документа и пр. Обратите внимание, что даты и время будут указаны в часовом поясе UTC+0.

Теперь поговорим о том, как можно проанализировать содержимое документа. Файлы с расширением docx обладают развитой внутренней структурой, которая в библиотеке docx представлена следующими объектами:

Объект Document, представляющий собой весь документ

  • Список объектов Paragraph – абзацы документа
    * Список объектов Run – фрагменты текста с различными стилями форматирования (курсив, цвет шрифта и т.п.)
  • Список объектов Table – таблицы документа
    * Список объектов Row – строки таблицы
    * Список объектов Cell – ячейки в строке
    * Список объектов Column – столбцы таблицы
    * Список объектов Cell – ячейки в столбце
  • Список объектов InlineShape – иллюстрации документа

Работа с текстом документа

Для начала давайте разберёмся, как работать с текстом документа. В библиотеке docx это возможно через обращение к абзацам документа. Можно получить как сам текст абзаца, так и его характеристики: тип выравнивания, величину отступов и интервалов, положение на странице.

Очень часто стоит задача получить весь текст из документа для дальнейшей обработки. Чтобы это сделать, достаточно лишь перебрать все абзацы документа:

text = [] for paragraph in doc.paragraphs: text.append(paragraph.text) print('\n'.join(text))

Как мы видим, для получения текста абзаца нужно просто обратиться к объекту paragraph.text. Но что же делать, если нужно извлечь только абзацы с определёнными характеристиками и далее работать именно с ними? Рассмотрим основные характеристики абзацев, которые можно проанализировать.

В первую очередь, можно получить стиль выравнивания абзацев в документе:

for paragraph in doc.paragraphs: print('Выравнивание абзаца:', paragraph.alignment)

Значения alignment будут соответствовать одному из основных стилей выравнивания: LEFT (0), center (1), RIGHT (2) или justify (3). Однако если пользователь не установил стиль выравнивания, значение параметра alignment будет None.

Кроме того, можно получить и значения отступов у абзацев документа:

for paragraph in doc.paragraphs: formatting = paragraph.paragraph_format print('Отступ перед абзацем:', formatting.space_before) print('Отступ после абзаца:', formatting.space_after) print('Отступ слева:', formatting.left_indent) print('Отступ справа:', formatting.right_indent) print('Отступ первой строки абзаца:', formatting.first_line_indent)

Как и в предыдущем примере, если отступы не были установлены, значения параметров будут None. В остальных случаях они будут представлены в виде целого числа в формате EMU (английские метрические единицы). Этот формат позволяет конвертировать число как в метрическую, так и в английскую систему мер. Привести полученные числа в привычный формат довольно просто, достаточно просто добавить нужные единицы исчисления после параметра (например, formatting.space_before.cm или formatting.space_before.pt). Главное помнить, что такое преобразование нельзя применять к значениям None.

Наконец, можно посмотреть на положение абзаца на странице. В меню Абзац… на вкладке Положение на странице находятся четыре параметра, значения которых также можно посмотреть при помощи библиотеки docx:

for paragraph in doc.paragraphs: formatting = paragraph.paragraph_format print('Не отрывать от следующего абзаца:', formatting.keep_with_next) print('Не разрывать абзац:', formatting.keep_together) print('Абзац с новой страницы:', formatting.page_break_before) print('Запрет висячих строк:', formatting.widow_control)

Параметры будут иметь значение None для случаев, когда пользователь не устанавливал на них галочки, и True, если устанавливал.

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

Можно получить список фрагментов с различными стилями форматирования (список объектов Run). Попробуем, к примеру, извлечь все фрагменты, написанные курсивом:

Очень просто, не так ли? Посмотрим, какие ещё стили форматирования можно извлечь:

Если пользователь не менял стиль форматирования (отсутствует подчёркивание, используется стандартный шрифт и т.п.), параметры будут иметь значение None. Но если стиль определённого параметра изменялся, то:

  • параметры italic, bold, underline, strike будут иметь значение True;
  • параметр font.name – наименование шрифта;
  • параметр font.color.rgb – код цвета текста в RGB;
  • параметр font.highlight_color – наименование цвета заливки текста.

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

Абзацы и их фрагменты могут быть оформлены в определённом стиле, соответствующем стилям Word (например, Normal, Heading 1, Intense Quote). Чем это может быть полезно? К примеру, обращение к стилям абзаца может пригодиться при выделении нумерованных или маркированных списков. Каждый элемент таких списков считается отдельным абзацев, однако каждому из них приписан особый стиль – List Paragraph. С помощью кода ниже можно извлечь только элементы списков:

for paragraph in doc.paragraphs: if paragraph.style.name == 'List Paragraph': print(paragraph.text)

Чтобы закрепить полученные знания, давайте разберём менее тривиальный случай. Предположим, что у нас есть множество документов с похожей структурой, из которых нужно извлечь названия продуктов. Проанализировав документы, мы установили, что продукты встречаются только в абзацах, начинающихся с новой страницы и выровненных по ширине. Притом сами названия написаны с использованием полужирного начертания, шрифт Arial Narrow. Посмотрим, как можно проанализировать документы:

В блоке кода выше последовательно обрабатываются все файлы из списка paths, преобразовываемые в ходе обработки в объект Document. В каждом документе происходит перебор абзацев и выполняются проверки: абзац должен начинаться с новой страницы и быть выровненным по ширине. Если проверки прошли успешно, внутри абзаца происходит уже перебор фрагментов с различными типами форматированием и проверки на начертание и шрифт.

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

Работа с таблицами

Мы рассмотрели способы, которыми можно обрабатывать текст в документах, а теперь давайте перейдём к обработке таблиц. Любую таблицу можно перебирать как по строкам, так и по столбцам. Посмотрим, как можно построчно получить текст каждой ячейки в таблице:

for table in doc.tables: for row in table.rows: for cell in row.cells: print(cell.text)

Если же во второй строке заменить rows на columns, то можно будет аналогичным образом прочитать таблицу по столбцам. Текст в ячейках таблицы тоже состоит из абзацев. Если мы захотим проанализировать абзацы или фрагменты внутри ячейки, то можно будет воспользоваться всеми методами объектов Paragraph и Run.

Часто может понадобиться проанализировать только таблицы, содержащие определённые заголовки. Попробуем, например, выделить из документа только таблицы, у которых в строке заголовка присутствуют названия Продукт и Стоимость. Для таких таблиц построчно распечатаем все значения из ячеек:

for table in doc.tables: for index, row in enumerate(table.rows): if index == 0: row_text = list(cell.text for cell in row.cells) if 'Продукт' not in row_text or 'Стоимость' not in row_text: break for cell in row.cells: print(cell.text)

Также нам может понадобиться определить, какие из ячеек в таблице являются объединёнными. Стандартной функции для этого нет, однако мы можем воспользоваться тем, что нам доступно положение ячейки от каждого из краев таблицы:

for table in doc.tables: unique, merged = set(), set() for row in table.rows: for cell in row.cells: tc = cell._tc cell_loc = (tc.top, tc.bottom, tc.left, tc.right) if cell_loc in unique: merged.add(cell_loc) else: unique.add(cell_loc) print(merged)

Воспользовавшись этим кодом, можно получить все координаты объединённых ячеек для каждой из таблиц документа. Кроме того, разница координат tc.top и tc.bottom показывает, сколько строк в объединённой ячейке, а разница tc.left и tc.right – сколько столбцов.

Наконец, рассмотрим возможность выделения из таблиц ячеек, в которых фон окрашен в определённый цвет. Для этого понадобится с помощью регулярных выражений посмотреть на xml-код ячейки:

Работа с иллюстрациями

В библиотеке docx также реализована возможность работы с иллюстрациями документа. Стандартными способами можно посмотреть только на размеры изображений:

for shape in doc.inline_shapes: print(shape.width, shape.height)

Однако при помощи сторонней библиотеки docx2txt и анализа xml-кода абзацев становится возможным не только выгрузить все иллюстрации документов, но и определить, в каком именно абзаце они встречались:

import os import docx import docx2txt for path in paths: splitted = os.path.split(path) folders = [os.path.splitext(splitted[1])[0]] while splitted[0]: splitted = os.path.split(splitted[0]) folders.insert(0, splitted[1]) images_path = os.path.join('images', *folders) os.makedirs(images_path, exist_ok=True) doc = docx.Document(path) docx2txt.process(path, images_path) rels = <> for rel in doc.part.rels.values(): if isinstance(rel._target, docx.parts.image.ImagePart): rels[rel.rId] = os.path.basename(rel._target.partname) for paragraph in doc.paragraphs: if 'Graphic' in paragraph._p.xml: for rId in rels: if rId in paragraph._p.xml: print(os.path.join(images_path, rels[rId])) print(paragraph.text)

В этом блоке мы выводим путь к изображению, которое сохранено на диске, и текст параграфа, в котором встретилось изображение. Все изображения находятся внутри директории images, а именно — в поддиректориях, соответствующих расположению исходного файла Word.


Файлы с расширением .docx обладают развитой внутренней структурой. В модуле python-docx эта структура представлена тремя различными типами данных. На самом верхнем уровне объект Document представляет собой весь документ. Объект Document содержит список объектов Paragraph , которые представляют собой абзацы документа. Каждый из абзацев содержит список, состоящий из одного или нескольких объектов Run , представляющих собой фрагменты текста с различными стилями форматирования.



Получаем весь текст из документа:

Стилевое оформление

В документах MS Word применяются два типа стилей: стили абзацев, которые могут применяться к объектам Paragraph , стили символов, которые могут применяться к объектам Run . Как объектам Paragraph , так и объектам Run можно назначать стили, присваивая их атрибутам style значение в виде строки. Этой строкой должно быть имя стиля. Если для стиля задано значение None , то у объекта Paragraph или Run не будет связанного с ним стиля.

Стили абзацев

  • Normal
  • Body Text
  • Body Text 2
  • Body Text 3
  • Caption
  • Heading 1
  • Heading 2
  • Heading 3
  • Heading 4
  • Heading 5
  • Heading 6
  • Heading 7
  • Heading 8
  • Heading 9
  • Intense Quote
  • List
  • List 2
  • List 3
  • List Bullet
  • List Bullet 2
  • List Bullet 3
  • List Continue
  • List Continue 2
  • List Continue 3
  • List Number
  • List Number 2
  • List Number 3
  • List Paragraph
  • Macro Text
  • No Spacing
  • Quote
  • Subtitle
  • TOCHeading
  • Title

Стили символов

  • Emphasis
  • Strong
  • Book Title
  • Default Paragraph Font
  • Intense Emphasis
  • Subtle Emphasis
  • Intense Reference
  • Subtle Reference

Атрибуты объекта Run

Отдельные фрагменты текста, представленные объектами Run , могут подвергаться дополнительному форматированию с помощью атрибутов. Для каждого из этих атрибутов может быть задано одно из трех значений: True (атрибут активизирован), False (атрибут отключен) и None (применяется стиль, установленный для данного объекта Run ).

  • bold — Полужирное начертание
  • underline — Подчеркнутый текст
  • italic — Курсивное начертание
  • strike — Зачеркнутый текст

Изменим стили для всех параграфов нашего документа:


А теперь восстановим все как было:


Изменим форматирвание объектов Run второго абзаца:


Запись докуменов MS Word

Добавление абзацев осуществляется вызовом метода add_paragraph() объекта Document . Для добавления текста в конец существующего абзаца, надо вызвать метод add_run() объекта Paragraph :


Оба метода, add_paragraph() и add_run() принимают необязательный второй аргумент, содержащий строку стиля, например:

Добавление заголовков

Вызов метода add_heading() приводит к добавлению абзаца, отформатированного в соответствии с одним из возможных стилей заголовков:


Аргументами метода add_heading() являются строка текста и целое число от 0 до 4. Значению 0 соответствует стиль заголовка Title .

Добавление разрывов строк и страниц

Чтобы добавить разрыв строки (а не добавлять новый абзац), нужно вызвать метод add_break() объекта Run . Если же требуется добавить разрыв страницы, то методу add_break() надо передать значение docx.enum.text.WD_BREAK.PAGE в качестве единственного аргумента:

Добавление изображений

Метод add_picture() объекта Document позволяет добавлять изображения в конце документа. Например, добавим в конец документа изображение kitten.jpg шириной 10 сантиметров:

Именованные аргументы width и height задают ширину и высоту изображения. Если их опустить, то значения этих аргументов будут определяться размерами самого изображения.

Читайте также: