Python-docx: автоматизация обработки Word документов

Раздел: Python -> Работа с документами

Основные возможности python-docx

Библиотека python-docx предназначена для создания, чтения и модификации документов формата DOCX. Она не требует установленного Microsoft Office и позволяет автоматизировать работу с текстом, таблицами, изображениями и стилями.

Базовое создание документа с текстом

Как создать простой документ и сохранить его?


from docx import Document

doc = Document()
doc.add_paragraph('Привет, мир!')
doc.save('example.docx')
  

Python docx библиотека (библиотека python-docx для работы с документами)

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

Типичная ошибка: если папка назначения не существует, python-docx выдаст ошибку FileNotFoundError. Перед сохранением следует убедиться, что каталог существует.

Чтение существующего документа

Как извлечь текст из файла .docx?


from docx import Document

doc = Document('existing.docx')
for paragraph in doc.paragraphs:
    print(paragraph.text)
  

Python документ word (работа с документами word в python (python-docx))

Метод paragraphs возвращает список всех абзацев документа. Для извлечения текста из таблиц нужно дополнительно перебирать строки и ячейки.

Проблема: если файл повреждён или не является DOCX, возникнет исключение docx.opc.exceptions.PackageNotFoundError. Рекомендуется проверять существование файла и его расширение.

Добавление таблицы

Как вставить таблицу с данными?


from docx import Document

doc = Document()
table = doc.add_table(rows=2, cols=3)
table.cell(0, 0).text = 'Имя'
table.cell(0, 1).text = 'Возраст'
table.cell(0, 2).text = 'Город'
table.cell(1, 0).text = 'Анна'
table.cell(1, 1).text = '25'
table.cell(1, 2).text = 'Москва'
doc.save('table_example.docx')
  

Таблица создаётся с указанным числом строк и столбцов. Для заполнения используется метод cell(row, col).text. Чтобы добавить границы, нужно настроить стиль таблицы (table.style = 'Light Grid Accent 1').

Ошибка: если обратиться к несуществующей ячейке (например, row=10), возникнет IndexError. Следует контролировать размеры таблицы.

Форматирование текста (шрифт, размер, жирность)

Как изменить начертание текста в абзаце?


from docx import Document
from docx.shared import Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH

doc = Document()
p = doc.add_paragraph('Важный текст')
run = p.runs[0]
run.font.size = Pt(16)
run.font.bold = True
run.font.name = 'Arial'
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
doc.save('formatted.docx')
  

Абзац состоит из run (непрерывный сегмент текста). Свойства шрифта задаются через объект run.font. Выравнивание устанавливается для всего абзаца.

Проблема: если текст состоит из нескольких run (например, из-за разных стилей внутри абзаца), изменение первого run может не повлиять на остальные. Нужно перебирать все runs.

Вставка изображения

Как добавить картинку в документ?


from docx import Document
from docx.shared import Inches

doc = Document()
doc.add_picture('image.png', width=Inches(4.0), height=Inches(3.0))
doc.save('image_doc.docx')
  

Изображение добавляется в текущую позицию (обычно в новый абзац). Размер можно задать в дюймах, сантиметрах (Cm) или пунктах (Pt).

Ошибка: если файл изображения не найден, возникнет FileNotFoundError. Поддерживаются форматы PNG, JPEG, GIF, BMP. Для больших изображений рекомендуется указывать точные размеры, чтобы избежать растяжения.

Работа с разделами и колонтитулами

Как задать ориентацию страницы или добавить верхний колонтитул?


from docx import Document
from docx.shared import Inches, Pt
from docx.enum.section import WD_ORIENT

doc = Document()
section = doc.sections[0]
section.orientation = WD_ORIENT.LANDSCAPE
section.page_width = Inches(11.69)
section.page_height = Inches(8.27)

header = section.header
header.is_linked_to_previous = False
hp = header.paragraphs[0]
hp.text = 'Колонтитул'
hp.style = doc.styles['Header']

doc.save('section_header.docx')
  

Каждый раздел имеет свои параметры страницы. Колонтитулы (верхний/нижний) доступны через section.header / section.footer. Свойство is_linked_to_previous отключает связь с предыдущим разделом.

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

Использование стилей и создание собственных

Как применить готовый стиль или создать свой?


from docx import Document
from docx.shared import Pt, RGBColor
from docx.enum.style import WD_STYLE_TYPE

doc = Document()
style = doc.styles['Normal']
style.font.size = Pt(12)
style.font.name = 'Calibri'

new_style = doc.styles.add_style('MyStyle', WD_STYLE_TYPE.PARAGRAPH)
new_style.font.size = Pt(14)
new_style.font.color.rgb = RGBColor(0xFF, 0x00, 0x00)
p = doc.add_paragraph('Красный текст', style='MyStyle')

doc.save('styles.docx')
  

Встроенные стили (Normal, Heading1 и др.) можно изменять. Новые стили создаются методом add_style. Тип стиля может быть параграф, символ (run), таблица, список.

Ошибка: если стиль с таким именем уже существует, возникнет KeyError. Перед добавлением стоит проверять наличие: if 'MyStyle' not in [s.name for s in doc.styles]: ...

Расширенные примеры использования python-docx

Создание документа с оглавлением (TOC)

python-docx не имеет встроенной поддержки оглавления (поле TOC), но можно добавить поле вручную через XML. Пример:

Пример

from docx import Document
from docx.oxml.ns import qn
from docx.oxml import OxmlElement

doc = Document()
doc.add_heading('Глава 1', level=1)
doc.add_paragraph('Текст главы 1')
doc.add_heading('Глава 2', level=1)
doc.add_paragraph('Текст главы 2')

# Вставка поля TOC в пустой абзац
p = doc.add_paragraph()
run = p.add_run()
fldChar1 = OxmlElement('w:fldChar')
fldChar1.set(qn('w:fldCharType'), 'begin')
run._r.append(fldChar1)

run2 = p.add_run()
instrText = OxmlElement('w:instrText')
instrText.set(qn('xml:space'), 'preserve')
instrText.text = ' TOC \\o "1-3" \\h \\z \\u '
run2._r.append(instrText)

run3 = p.add_run()
fldChar2 = OxmlElement('w:fldChar')
fldChar2.set(qn('w:fldCharType'), 'end')
run3._r.append(fldChar2)

doc.save('toc_doc.docx')

После открытия в Word нужно обновить поля (Ctrl+A, F9). В коде используется работа с XML OpenXML для создания поля.

Использование закладок (bookmarks)

Для создания закладок также требуется манипуляция с XML:

Пример

from docx import Document
from docx.oxml.ns import qn
from docx.oxml import OxmlElement

doc = Document()
p = doc.add_paragraph('Текст с закладкой')
run = p.runs[0]

# Создаём элемент bookmarkStart
bm_start = OxmlElement('w:bookmarkStart')
bm_start.set(qn('w:id'), '0')
bm_start.set(qn('w:name'), 'MyBookmark')
run._r.addprevious(bm_start)

# bookmarkEnd
bm_end = OxmlElement('w:bookmarkEnd')
bm_end.set(qn('w:id'), '0')
run._r.addnext(bm_end)

doc.save('bookmark.docx')

После вставки закладки на неё можно ссылаться из гиперссылок или макросов Word.

Объединение нескольких документов

Можно скопировать содержимое одного документа в другой, используя внутренние объекты:

Пример

from docx import Document

doc1 = Document('doc1.docx')
doc2 = Document('doc2.docx')

for element in doc2.element.body:
    doc1.element.body.append(element)

doc1.save('merged.docx')

Внимание: этот способ копирует всё тело документа, включая секции и колонтитулы, что может нарушить структуру. Рекомендуется копировать только содержимое (параграфы, таблицы) через изучение структуры.

Создание сложной таблицы с объединением ячеек

Для объединения ячеек используйте методы merge:

Пример

from docx import Document
from docx.shared import Inches

doc = Document()
table = doc.add_table(rows=3, cols=3)
table.cell(0, 0).merge(table.cell(0, 1))
table.cell(0, 0).text = 'Объединённая ячейка'
table.cell(1, 0).text = 'A'
table.cell(1, 1).text = 'B'
table.cell(1, 2).text = 'C'
# Установка стиля
from docx.enum.table import WD_TABLE_ALIGNMENT
table.alignment = WD_TABLE_ALIGNMENT.CENTER
doc.save('merged_table.docx')

Метод merge принимает другую ячейку и возвращает объект объединённой ячейки. После объединения индексы строк/столбцов могут сместиться.

Заполнение шаблона (mail merge) с помощью замены текста

Простой способ: подготовить документ с плейсхолдерами вида {{name}} и заменить их:

Пример

from docx import Document

doc = Document('template.docx')
placeholders = {'{{name}}': 'Анна', '{{city}}': 'Москва'}

for paragraph in doc.paragraphs:
    for key, value in placeholders.items():
        if key in paragraph.text:
            paragraph.text = paragraph.text.replace(key, value)

# Также замена в таблицах
for table in doc.tables:
    for row in table.rows:
        for cell in row.cells:
            for key, value in placeholders.items():
                if key in cell.text:
                    cell.text = cell.text.replace(key, value)

doc.save('filled.docx')

Недостаток: при такой замене теряется форматирование исходного текста (run properties). Для сохранения форматирования нужно работать с XML каждого run.

Работа с XML напрямую (пример: изменение цвета страницы)

Можно модифицировать низкоуровневые свойства документа через lxml:

Пример

from docx import Document
from docx.oxml.ns import qn

doc = Document()
section = doc.sections[0]
sectPr = section._sectPr

# Добавляем цвет фона страницы
sectPr.set(qn('w:pgBorders'), '')

# Или добавить элемент background
from lxml import etree
bg = etree.SubElement(sectPr, qn('w:background'))
bg.set(qn('w:color'), 'FFFF00')

doc.save('colored_bg.docx')

Эти манипуляции требуют знания структуры OOXML.

Создание нумерованного или маркированного списка

Пример

from docx import Document
from docx.enum.text import WD_NUMBER_STYLE
from docx.oxml.ns import qn
from docx.oxml import OxmlElement

doc = Document()
# Для списка используем абзацы с отступом и стилем List Number
for i in range(1, 4):
    p = doc.add_paragraph(f'Пункт {i}', style='List Number')
doc.save('numbered_list.docx')

Можно также создавать многоуровневые списки, настраивая numPr через XML.

Результат выполнения кода (пример вывода на консоль)

Некоторые примеры не возвращают результат в консоль, а создают файл. Для демонстрации можно использовать следующий код чтения текста:

Пример

from docx import Document
doc = Document('example.docx')
for p in doc.paragraphs:
    print(p.text)
Привет, мир!

Библиотека Python-docx для работы с документами - comments

En
Python docx библиотека (python)