Точное управление шрифтами в Word с помощью Python: получение и замена
В процессе обработки документов Word управление шрифтами является одной из самых частых задач. Будь то проверка, какие шрифты используются в отчёте, или единообразная замена одного шрифта на другой по всему документу — ручные правки отнимают много времени и чреваты ошибками. Благодаря библиотеке Free Spire.Doc for Python мы можем программно считывать и заменять информацию о шрифтах, автоматизируя этот процесс. В этой статье на двух практических примерах мы разберём, как это делается.
1. Почему Free Spire.Doc
Free Spire.Doc for Python — это профессиональный инструмент для работы с документами Word, не требующий установки Microsoft Office. Он позволяет создавать, изменять, конвертировать и извлекать содержимое файлов .docx прямо из Python. Объектная модель библиотеки полностью повторяет структуру Word:
- Document содержит один или несколько Section;
- каждый Section включает Body;
- Body состоит из Paragraph;
- каждый абзац содержит дочерние объекты ChildObject — это могут быть TextRange (текстовые фрагменты), таблицы, изображения и т.д.
Именно в TextRange хранится форматирование шрифта через свойство CharacterFormat, где доступны:
- FontName — имя шрифта,
- FontSize — размер в пунктах,
- TextColor — цвет текста.
Чёткая иерархия упрощает обход всех элементов и внесение изменений.
2. Сценарий 1: получение списка всех шрифтов в документе
Первый скрипт сканирует документ, извлекает для каждого текстового фрагмента имя шрифта, размер и цвет, удаляет дубликаты и сохраняет результат в текстовый файл. Это полезно для аудита соответствия корпоративному стандарту или для проверки, не закрались ли посторонние шрифты.
from spire.doc import *
from spire.doc.common import *
# Функция для записи строк в txt-файл
def WriteAllText(fname:str, text:List[str]):
fp = open(fname, «w», encoding="utf-8″)
for s in text:
fp.write(s)
# Пользовательский класс для хранения информации о шрифте
class FontInfo:
def __init__(self):
self._m_name = ’’
self._m_size = None
def __eq__(self, other):
if isinstance(other, FontInfo):
return self._m_name == other.get_name() and self._m_size == other.get_size()
return False
def get_name(self):
return self._m_name
def set_name(self, value):
self._m_name = value
def get_size(self):
return self._m_size
def set_size(self, value):
self._m_size = value
# Переменные для сбора данных
fontInformations = ""
font_infos = []
document = Document()
document.LoadFromFile("Input.docx")
# Обход всех разделов
for i in range(document.Sections.Count):
section = document.Sections.get_Item(i)
# Обход абзацев в разделе
for j in range(section.Body.Paragraphs.Count):
paragraph = section.Body.Paragraphs.get_Item(j)
# Обход дочерних объектов абзаца
for k in range(paragraph.ChildObjects.Count):
obj = paragraph.ChildObjects.get_Item(k)
# Нас интересуют только текстовые диапазоны
if isinstance(obj, TextRange):
txtRange = obj if isinstance(obj, TextRange) else None
fontName = txtRange.CharacterFormat.FontName
fontSize = txtRange.CharacterFormat.FontSize
textColor = txtRange.CharacterFormat.TextColor.Name
# Дедупликация по паре (имя, размер)
fontInfo = FontInfo()
fontInfo.set_name(fontName)
fontInfo.set_size(fontSize)
if fontInfo not in font_infos:
font_infos.append(fontInfo)
str = "Шрифт: {0:s}, Размер: {1:f} пт, Цвет: {2:s}".format(
fontInfo.get_name(), fontInfo.get_size(), textColor)
fontInformations += str
fontInformations += ’\n’
WriteAllText("Список_шрифтов.txt«, fontInformations)
document.Dispose()
Как это работает
- Загружаем документ методом LoadFromFile.
- В трёх вложенных циклах перебираем разделы → абзацы → дочерние объекты.
- Фильтруем объекты типа TextRange — только они содержат шрифтовые атрибуты.
- Извлекаем FontName, FontSize и TextColor.Name.
- Для исключения дубликатов используется класс FontInfo с переопределённым __eq__ (уникальность определяется по паре «имя + размер»). Цвет не участвует в сравнении, так как один и тот же шрифт может использоваться с разными цветами.
- Результат записывается в текстовый файл.
Пример вывода (после запуска на типичном русскоязычном документе):
Шрифт: Times New Roman, Размер: 12.000000 пт, Цвет: Чёрный
Шрифт: Arial, Размер: 10.500000 пт, Цвет: Красный
Шрифт: Calibri, Размер: 11.000000 пт, Цвет: Чёрный
3. Сценарий 2: замена одного шрифта на другой
Второй пример заменяет во всём документе шрифт Times New Roman на Arial. Это частая задача при приведении отчётов к единому стилю или при подготовке документов для систем, где предпочтителен sans‑serif.
from spire.doc import *
from spire.doc.common import *
document = Document()
document.LoadFromFile("Input.docx«)
for i in range(document.Sections.Count):
section = document.Sections.get_Item(i)
for j in range(section.Body.Paragraphs.Count):
paragraph = section.Body.Paragraphs.get_Item(j)
for k in range(paragraph.ChildObjects.Count):
obj = paragraph.ChildObjects.get_Item(k)
if isinstance(obj, TextRange):
txtRange = obj if isinstance(obj, TextRange) else None
fontName = txtRange.CharacterFormat.FontName
# Если шрифт — Times New Roman, меняем на Arial
if (fontName == «Times New Roman»):
txtRange.CharacterFormat.FontName = «Arial»
document.SaveToFile("ReplaceFont.docx«, FileFormat.Docx)
document.Dispose()
Логика замены
- Обход структуры аналогичен первому сценарию.
- При обнаружении TextRange проверяется его FontName.
- При совпадении с заданным значением («Times New Roman») свойству присваивается новое имя («Arial»).
- Остальное форматирование (жирность, наклон, цвет) сохраняется, так как они независимы.
Важные замечания :
- Шрифт Arial должен быть установлен в системе или встроен в документ, иначе Word подставит запасной.
- Если требуется заменить только в определённых разделах или абзацах, можно добавить дополнительные фильтры (например, по стилю).
- Для массовой замены нескольких шрифтов удобно использовать словарь соответствий.
4. Сравнение подходов и их комбинация
Оба скрипта можно использовать последовательно: сначала получить список всех шрифтов, затем решить, какие из них нужно заменить, и применить второй скрипт. При необходимости можно объединить логику, например, заменять только те шрифты, у которых размер больше 12 пт.
5. Рекомендации по улучшению кода
- Упрощение дедупликации — если цвет не нужен, можно хранить кортежи (fontName, fontSize) в множестве, избавившись от отдельного класса.
- Обработка исключений — оберните загрузку и сохранение в try...except, чтобы перехватывать ошибки доступа или повреждённые файлы.
- Пакетная обработка — заключите основную логику в функцию и вызывайте её для списка файлов.
- Освобождение ресурсов — всегда вызывайте Dispose(), особенно при работе с большим количеством документов, чтобы избежать утечек памяти.
6. Заключение
Используя Free Spire.Doc for Python, мы всего за несколько десятков строк кода научились получать и заменять шрифты в документах Word. Эти приёмы легко встраиваются в автоматизированные рабочие процессы — от проверки корпоративных шаблонов до массовой подготовки документов к типографии. Предложенные примеры уже адаптированы под реалии русскоязычных пользователей: в них фигурируют стандартные шрифты (Times New Roman, Arial, Calibri) и русские названия цветов. Вы можете доработать код под свои нужды, добавив обработку таблиц, колонтитулов или стилей абзацев. Автоматизация рутинных задач с помощью Python и Spire.Doc — это надёжный способ сэкономить время и исключить человеческий фактор.