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

Добавление и извлечение таблиц при помощи модуля python-docx

Содержание:


Добавление табличных данных в документ DOCX.

При создании документа DOCX, часто встречается контент, который необходимо представить в виде аккуратной таблицы. Редактор MS Word неплохо справляется с этим. А вот как добавить таблицу при помощи модуля python-docx:

Пример добавления пустой таблицы, содержащей 2х2 ячейки:

from docx import Document

# создание пустого документа
doc = Document()
# добавляем пустую таблицу 2х2 ячейки
table = doc.add_table(rows=2, cols=2)

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

cell = table.cell(0, 1)

Этот код возвратит объект ячейки Cell, которая расположена справа в верхней строке таблицы. Обратите внимание, что индексы строк и столбцов начинаются с нуля, как в списке.

В полученный объект ячейки можно записать какие-нибудь данные:

# добавляем данные как прогон абзаца 
# и выделяем текст жирным 
cell.paragraphs[0].add_run('Бык').bold = True

# можно записать данные в ячейку проще 
cell.text = 'Бык'
# что бы теперь отформатировать текст, нужно 
# получить доступ к свойствам прогона ячейки
rc = cell.paragraphs[0].runs[0]
rc.font.name = 'Arial'
rc.font.bold = True

Часто бывает проще получить доступ к ряду ячеек одновременно, например, при заполнении таблицы переменной длины из источника данных. Свойство таблицы Table.rows предоставляет доступ к отдельным строкам, каждая из которых имеет свойство Table.rows[i].cells. Свойство .cells как в строке, так и в столбце поддерживает доступ к ячейке по индексу (как с списку):

# получаем 2-ю строку таблицы
row = table.rows[1]
# запись данных в ячейки
row.cells[0].text = 'Заяц'
row.cells[1].text = 'Волк'

Последовательности Table.rows и Table.columns в таблице являются итерируемыми, следовательно можно использовать их непосредственно в цикле for. То же самое с последовательностями ячеек, например для первой строки таблицы Table.rows[0].cells или для первого столбца Table.columns[0].cells:

# читаем ячейки таблицы `table`
for row in table.rows:
    for cell in row.cells:
        print(cell.text)

Если необходимо узнать количество строк или столбцов в таблице, то просто используйте функцию len() для соответствующей последовательности:

# количество строк в таблице
row_count = len(table.rows)
# количество колонок в таблице
col_count = len(table.columns)

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

row = table.add_row()

Это может быть очень удобно для построения таблицы переменной длины:

# полноценный рабочий код
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH

# создание пустого документа
doc = Document()
# данные таблицы без названий колонок
items = (
    (7, '1024', 'Плюшевые котята'),
    (3, '2042', 'Меховые пчелы'),
    (1, '1288', 'Ошейники для пуделей'),
)
# добавляем таблицу с одной строкой 
# для заполнения названий колонок
table = doc.add_table(1, len(items[0]))
# определяем стиль таблицы
table.style = 'Light Shading Accent 1'
# Получаем строку с колонками из добавленной таблицы 
head_cells = table.rows[0].cells
# добавляем названия колонок
for i, item in enumerate(['Кол-во', 'ID', 'Описание']):
    p = head_cells[i].paragraphs[0]
    # название колонки
    p.add_run(item).bold = True
    # выравниваем посередине
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
# добавляем данные к существующей таблице
for row in items:
    # добавляем строку с ячейками к объекту таблицы
    cells = table.add_row().cells
    for i, item in enumerate(row):
        # вставляем данные в ячейки
        cells[i].text = str(item)
        # если последняя ячейка
        if i == 2:
            # изменим шрифт
            cells[i].paragraphs[0].runs[0].font.name = 'Arial'
doc.save('test.docx')

То же самое работает для столбцов, хотя строить таблицу таким способом не удобно.

MS Word имеет набор предварительно отформатированных стилей таблиц, которые можно выбрать из его галереи стилей таблиц. Применить один из них к таблице можно следующим образом:

table.style = 'Light Shading Accent 1'

Обратите внимание, что имя стиля таблицы немного отличается от имени, отображаемого в пользовательском интерфейсе MS Word. Дефис, если он есть, то его необходимо удалить. Например, Light Shading - Accent 1 становится Light Shading Accent 1.

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

Важно!!! Встроенные стили хранятся в файле WordprocessingML под своим английским именем, например 'Table Grid', и не зависят от локализации MS Word. Так как модуль python-docx работает с файлом WordprocessingML, то поиск стиля должен использовать английское имя. Если файл WordprocessingML не найден (MS Word не установлен, например в OS Linux) то модуль python-docx работает со своей версией этого файла. Что бы создать сопоставление между именами стилей на русском языке и именами на английском языке посетите эту ссылку.

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

>>> from docx import Document
>>> from docx.enum.style import WD_STYLE_TYPE
>>> doc = Document()
>>> all_styles = doc.styles
>>> table_styles = [s for s in all_styles if s.type == WD_STYLE_TYPE.TABLE]
>>> for style in table_styles:
...   print(table_styles.name)
# Normal Table
# Table Grid
# Light Shading
# Light Shading Accent 1

Извлечение табличных данных их документов DOCX.

При чтении существующего документа DOCX, все находящиеся в нем объекты таблиц Table группируются в последовательности Document.tables. Следовательно, что бы узнать количество таблиц в документе, нужно вызвать функцию len() для этой последовательности.

Доступ к объектам таблиц будем осуществлять по индексу последовательности Document.tables.

Смотрим пример:

# полноценный рабочий код
from docx import Document

doc = Document('test.docx')
# последовательность всех таблиц документа
all_tables = doc.tables
print('Всего таблиц в документе:', len(all_tables))

# создаем пустой словарь под данные таблиц
data_tables = {i:None for i in range(len(all_tables))}
# проходимся по таблицам
for i, table in enumerate(all_tables):
    print('\nДанные таблицы №', i)
    # создаем список строк для таблицы `i` (пока пустые)
    data_tables[i] = [[] for _ in range(len(table.rows))]
    # проходимся по строкам таблицы `i`
    for j, row in enumerate(table.rows):
        # проходимся по ячейкам таблицы `i` и строки `j`
        for cell in row.cells:
            # добавляем значение ячейки в соответствующий
            # список, созданного словаря под данные таблиц
            data_tables[i][j].append(cell.text)

    # смотрим извлеченные данные 
    # (по строкам) для таблицы `i`
    print(data_tables[i])
    print('\n')

print('Данные всех таблиц документа:')
print(data_tables)