SmartDocGen: Автоматизация работы с Excel и Word > Полезное > Бесплатные способы генерации документов: VBA, Python, надстройки — честный разбор

Бесплатные способы генерации документов: VBA, Python, надстройки — честный разбор

Задача «делать документы по шаблону из таблицы» решается бесплатно. Не «почти», не «в урезанном виде» — полностью. Ниже два рабочих способа с полным кодом, который можно скопировать и запустить сегодня.

И вторая половина статьи — о том, во что бесплатное обходится на самом деле. Не для того, чтобы отговорить: если ваш случай простой, берите код и не читайте дальше.

Что нам понадобится

Оба примера работают с одинаковой парой файлов, чтобы их можно было сравнить честно.

Таблица Данные.xlsx — первая строка заголовки, дальше строки данных. Колонки: ФИО, Должность, Дата, Сумма, Имя файла. Последняя служебная — из неё берётся имя готового документа.

Шаблон Шаблон.docx — обычный документ Word, в котором на месте переменных стоят метки в двойных фигурных скобках: {{ФИО}}, {{Должность}}, {{Дата}}, {{Сумма}}. Имена меток совпадают с заголовками колонок.

Оба файла лежат в одной папке. Результат складывается в подпапку.

Один момент отмечу заранее, потому что он определяет всё дальнейшее: Word имеет привычку незаметно разрывать текст на фрагменты. Метка, которую вы видите как {{ФИО}}, внутри файла может храниться как три куска: {{, ФИ, О}}. Происходит это после правок, проверки орфографии, смены языка. Визуально не проявляется никак. Про разметку шаблона подробнее — в отдельной статье.

Способ первый: макрос VBA

Живёт внутри книги Excel, ничего дополнительно ставить не нужно. Управляет Word через автоматизацию — то есть Word должен быть установлен.

Как запустить: открыть книгу, нажать Alt+F11, вставить модуль (Insert → Module), вставить код, запустить F5. Книгу сохранить в формате .xlsm — обычный .xlsx макросы не хранит.

Option Explicit Sub СоздатьДокументы() Dim ws As Worksheet, wd As Object, doc As Object Dim lastRow As Long, lastCol As Long, i As Long, c As Long Dim tplPath As String, outDir As String Dim key As String, val As String Dim nameCol As Long, fileName As String Set ws = ThisWorkbook.Worksheets(1) tplPath = ThisWorkbook.Path & "\Шаблон.docx" outDir = ThisWorkbook.Path & "\Готовые" If Dir(outDir, vbDirectory) = "" Then MkDir outDir lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column ' служебная колонка с именем файла nameCol = 0 For c = 1 To lastCol If LCase(Trim(ws.Cells(1, c).Value)) = "имя файла" Then nameCol = c Next c Set wd = CreateObject("Word.Application") wd.Visible = False wd.DisplayAlerts = 0 For i = 2 To lastRow Set doc = wd.Documents.Add(tplPath) ' новый документ на основе шаблона For c = 1 To lastCol key = "{{" & Trim(ws.Cells(1, c).Value) & "}}" val = ws.Cells(i, c).Text ' .Text, а не .Value — сохраняет формат ячейки With doc.Content.Find .ClearFormatting .Replacement.ClearFormatting .Text = key .Replacement.Text = val .Forward = True .Wrap = 1 ' wdFindContinue .MatchCase = False .Execute Replace:=2 ' wdReplaceAll End With Next c If nameCol > 0 Then fileName = ЧистоеИмя(ws.Cells(i, nameCol).Text) Else fileName = "Документ" End If doc.SaveAs2 outDir & "\" & fileName & " row" & (i - 1) & ".docx", 16 doc.Close False Next i wd.Quit Set wd = Nothing MsgBox "Готово. Создано документов: " & (lastRow - 1), vbInformation End Sub Private Function ЧистоеИмя(ByVal s As String) As String Dim bad As Variant, k As Long bad = Array("<", ">", ":", """", "/", "\", "|", "?", "*") For k = LBound(bad) To UBound(bad) s = Replace(s, bad(k), "_") Next k ЧистоеИмя = Trim(s) End Function

Два места в этом коде стоят отдельного внимания.

doc.Content.Find справляется с разорванными метками. Это не случайность: поиск Word работает по тексту документа, а не по внутренним фрагментам, поэтому разбитая на куски метка находится и заменяется. Большое преимущество способа, о котором обычно не пишут.

.Text вместо .Value. Свойство .Value вернёт сырое число — 45000. Свойство .Text вернёт то, что видно в ячейке с учётом её формата — 45 000,00. Для сумм и дат это решает вопрос форматирования целиком.

Ограничения: нужен установленный Word, работает только на Windows, каждый документ открывается через настоящий Word — то есть скорость измеряется секундами на документ, а не миллисекундами. И макросы во многих организациях заблокированы политиками безопасности, а файл .xlsm почтовые фильтры любят не пропускать.

Способ второй: Python и python-docx

Word не нужен вовсе — библиотека работает с файлом .docx напрямую. Значит, код одинаково идёт на Windows, macOS и Linux и на сервере тоже.

Установка: pip install python-docx openpyxl

Сначала — как делать не надо, потому что именно этот вариант расходится по интернету:

for p in doc.paragraphs: for r in p.runs: # <- здесь и ломается for k, v in data.items(): r.text = r.text.replace("{{%s}}" % k, v)

Код выглядит логично и на простом шаблоне работает. Но как только Word разорвал метку на фрагменты, ни один фрагмент целиком её не содержит — и замена не срабатывает. В документе остаётся {{ФИО}} открытым текстом. Проверять это на трёх строках бесполезно: пока шаблон не правили, метки целые.

Рабочий вариант заменяет текст на уровне абзаца:

# -*- coding: utf-8 -*- # Генерация документов Word по шаблону из таблицы Excel. # Требуется: pip install python-docx openpyxl import os, re, datetime from openpyxl import load_workbook from docx import Document BASE = os.path.dirname(os.path.abspath(__file__)) TABLE = os.path.join(BASE, "Данные.xlsx") TPL = os.path.join(BASE, "Шаблон.docx") OUT = os.path.join(BASE, "Готовые") BAD = r'<>:"/\|?*' def fmt(v): """Значение ячейки -> строка. Числа с копейками — с разделителем разрядов.""" if v is None: return "" if isinstance(v, datetime.datetime): return v.strftime("%d.%m.%Y") if isinstance(v, float): s = f"{v:,.2f}".replace(",", "\u00a0").replace(".", ",") return s if isinstance(v, int): return f"{v:,}".replace(",", "\u00a0") return str(v) def safe(name): for ch in BAD: name = name.replace(ch, "_") return name.strip() or "Документ" def replace_in_paragraph(p, data): """Метка может быть разорвана Word'ом на несколько run'ов, поэтому заменяем по тексту всего абзаца, а не по каждому run отдельно.""" full = "".join(r.text for r in p.runs) if "{{" not in full: return new = re.sub(r"\{\{([^{}]+)\}\}", lambda m: data.get(m.group(1).strip(), m.group(0)), full) if new == full: return p.runs[0].text = new # форматирование берётся от первого run'а for r in p.runs[1:]: r.text = "" def replace_everywhere(doc, data): for p in doc.paragraphs: replace_in_paragraph(p, data) for t in doc.tables: for row in t.rows: for cell in row.cells: for p in cell.paragraphs: replace_in_paragraph(p, data) for s in doc.sections: # колонтитулы for part in (s.header, s.footer, s.first_page_header, s.first_page_footer): if part is None: continue for p in part.paragraphs: replace_in_paragraph(p, data) def main(): os.makedirs(OUT, exist_ok=True) ws = load_workbook(TABLE, data_only=True).active headers = [str(c.value).strip() if c.value is not None else "" for c in ws[1]] made = 0 for i, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=1): if all(v is None for v in row): continue data = {h: fmt(v) for h, v in zip(headers, row) if h} doc = Document(TPL) replace_everywhere(doc, data) name = safe(data.get("Имя файла", "")) or "Документ" doc.save(os.path.join(OUT, f"{name} row{i}.docx")) made += 1 print(f"создано документов: {made}, папка: {OUT}") if __name__ == "__main__": main()

Последовательность   в листинге — это неразрывный пробел: в русской типографике разряды в числах разделяются именно им, иначе «45 000,00» может переломиться посередине строки. Обычный пробел тоже сработает, но выглядеть будет хуже.

Что тут важно понимать.

Форматирование чисел приходится делать самому. Библиотека чтения Excel отдаёт сырое значение — 45000, а не 45 000,00. Формат ячейки, который вы настроили в таблице, до документа не доедет: функция fmt в примере воспроизводит его вручную. Это ровно та работа, которой в первом способе не было.

Замена по абзацу теряет форматирование внутри абзаца. Если в одном предложении часть слов жирная, после замены весь абзац примет оформление первого фрагмента. Для типовых документов это незаметно, для сложной вёрстки — придётся усложнять код.

Про скорость: сто документов по этому шаблону формируются за 7,4 секунды — около 70 миллисекунд на документ. Word при этом не запускается вовсе.

Бесплатные надстройки: на что смотреть

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

  • Когда было последнее обновление. Форматы офисных файлов меняются, заброшенная надстройка ломается на очередной версии Word.
  • Не уходят ли данные наружу. Бесплатная надстройка может быть витриной облачного сервиса, и тогда таблица уезжает на сервер. Для кадровых данных это меняет всё — почему именно, разобрано отдельно.
  • Есть ли исходный код. Открытый код можно хотя бы посмотреть или отдать на проверку безопасникам.
  • Что с макросами. Если надстройка распространяется как файл с макросами, вы упрётесь в те же политики безопасности, что и с VBA.
  • Кто починит. У бесплатного нет поддержки по договору. Это нормально ровно до того дня, когда что-то перестало работать перед сдачей отчётности.

Сколько стоит бесплатное

Код выше действительно бесплатный. Платите вы временем, и его стоит посчитать честно — в обе стороны.

ЭтапПервый разДальше
Разобраться, вставить, запустить1–2 часа
Довести под свой шаблон и колонки1–3 часа~0,5 часа на новый вид документа
Поймать разорванные метки и формат чисел1–2 часа
Добавить картинки в документыот 4 часов
Починить после смены шаблона0,5–2 часа за раз
Передать коллеге, когда вы в отпускеотдельная история

Итого на старте обычно выходит рабочий день. Цифры не универсальные — они зависят от того, насколько вам привычен код, — но порядок именно такой.

Дальше начинается то, о чём в момент «сейчас за вечер напишу» не думают.

Поддержка при смене шаблона. Юрист поменял формулировку и добавил поле — надо править код. Не сложно, но каждый раз это вы, и в тот момент, когда некогда.

Автобусный фактор. Скрипт написал один человек. Он в отпуске, документы нужны сегодня. Разбираться в чужом коде ради тридцати справок — не то, чем хочет заниматься кадровик.

Пограничные случаи. Пустая ячейка, объединённые ячейки, дата, введённая текстом, лишний пробел в заголовке колонки. Каждый вылезает по одному и каждый съедает время.

Картинки. Вставить фотографию в нужное место документа средствами python-docx можно, но это заметно больше кода, чем замена текста: нужно найти абзац, задать размеры, разобраться с ориентацией снимков с телефона. Это тот рубеж, на котором «за вечер» превращается в «за неделю».

Когда бесплатное — правильный выбор

Совершенно серьёзно, без подводки к продаже.

  • Задача разовая. Один раз сделать сорок документов — пишите скрипт или берите макрос, вопрос закрыт.
  • Вам это интересно. Разобраться с python-docx — полезный навык, который пригодится и в других задачах.
  • У вас есть разработчик. Час его времени дешевле согласования закупки.
  • Шаблон простой и стабильный. Текст без картинок, который не меняется годами.
  • Нестандартная логика. Если нужно что-то за пределами подстановки — свои правила, ветвления, обращение к базе, — код всё равно окажется гибче любой готовой программы.

Когда дешевле купить

Считать надо не «программа против нуля», а «программа против часов».

Возьмите стоимость часа того, кто будет писать и поддерживать код. Умножьте на восемь часов первичной настройки. Прибавьте по два часа в квартал на поддержку. Сравните с ценой готового инструмента за тот же период.

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

Признаки того, что расчёт уже не в пользу кода:

  • нужны картинки в документах — фотографии, подписи, печати;
  • шаблоны меняются несколько раз в год;
  • работать с этим будет не тот, кто писал;
  • макросы заблокированы политиками, а Python ставить некому;
  • видов документов больше трёх и они разные.

Если ничего из списка нет — берите код выше, он рабочий. Если есть половина — посчитайте.

Частые вопросы

Почему макрос заменяет метки, а Python-скрипт нет?

Word хранит текст абзаца фрагментами и после правок может разорвать метку на части: «{{», «ФИ», «О}}». Поиск Word работает по тексту документа целиком, поэтому находит разорванную метку. Наивный код на python-docx перебирает фрагменты по одному, и ни в одном из них метки целиком нет. Лечится заменой по тексту всего абзаца — так сделано в рабочем примере.

Почему в документ попадает 45000 вместо 45 000,00?

Потому что из ячейки берётся сырое значение, а не то, что вы видите. В VBA разница в свойстве: .Value даёт число, .Text — текст с учётом формата ячейки. В Python библиотека чтения Excel отдаёт сырое значение всегда, и форматирование приходится воспроизводить кодом.

Нужен ли установленный Word?

Для макроса VBA — да, он управляет настоящим Word и работает только на Windows. Для Python с библиотекой python-docx — нет: она работает с файлом .docx напрямую, поэтому код одинаково идёт на Windows, macOS, Linux и на сервере.

Сколько времени занимает написать это самому?

Если код вам привычен — рабочий день на первичную настройку под свои шаблоны и колонки, включая отладку пограничных случаев вроде пустых ячеек и разорванных меток. Дальше по полчаса на каждый новый вид документа и от получаса до двух часов при каждом изменении шаблона.

Можно ли этим кодом вставлять фотографии в документы?

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

Коротко

Оба способа выше рабочие, код полный, ничего не вырезано. Макрос VBA выигрывает в том, что использует поиск Word — разорванные метки и формат ячеек он обрабатывает сам. Python выигрывает в независимости от Word и в скорости: сто документов за 7,4 секунды против запуска Word на каждый файл.

Бесплатное стоит времени: примерно рабочий день на старте и по паре часов при каждом изменении шаблона. Пока задача разовая или простая — это выгодная сделка. Как только появляются картинки, несколько видов документов и необходимость передать всё коллеге, счёт меняется.

Смежные материалы: как размечать шаблон Word с готовыми файлами, пределы штатного слияния, чек-лист выбора инструмента.

SmartDocGen делает то же самое без кода: берёт формат прямо из ячейки Excel, обрабатывает метки в таблицах и колонтитулах, вставляет картинки по имени файла в колонке. Условной логики и склонения падежей в нём нет — это готовится в таблице.

Бесплатного демо-режима нет: установщик скачивается свободно, но нужен код активации. Сравнить со своим скриптом дешевле всего по тарифу на месяц — 399 ₽.

Посмотрите, как SmartDocGen работает на практике

В статье мы разобрали поставленную задачу. А здесь вы можете увидеть реальный пример: за несколько секунд программа превращает Excel-таблицу в десятки готовых документов:
03:51
В видео вы увидите, как SmartDocGen:
  • Создаёт сотни документов меньше чем за минуту
  • Сохраняет все шрифты, стили и форматирование
  • Одинаково хорошо работает с Excel и Word-шаблонами
Пошагово процесс выглядит так:
  • Загружается Excel-файл или таблица Word с данными
  • Указывается папка с шаблонами Word и изображениями
  • Задаётся папка для сохранения готовых документов
  • Запускается автоматическая обработка
Готовые файлы формируются мгновенно и сохраняют нужное оформление, структуру и имена.
Хочу так же — купить за 399₽/месяц
Установка 2 минуты. Возврат 100% в течение 14 дней
Просто нажмите и получите результат
Всего 4 кнопки — и документы формируются автоматически, с нужным оформлением и названиями.
Получить сейчас

Автоматизируйте документы по лучшей цене

Выберите подходящий срок лицензии — функционал во всех тарифах одинаково полный: массовая обработка Excel и Word, сохранение форматирования, поддержка и обновления.
Тариф "На 1 год"
Период действия: 12 месяцев
2990₽
Выгода 38% (экономия 1798₽)
Полный функционал программы:
  • Массовая обработка Excel → Word и Excel → PNG/JPEG
  • Неограниченное кол-во документов и изображений
  • Техподдержка + обновления (12 мес.)
Приобрести
⭐⭐⭐
Работает на:
Тариф "На 3 месяца"
Период действия: 3 месяца
990₽
Выгода 17% (экономия 207₽)
Полный функционал программы:
  • Массовая обработка Excel → Word и Excel → PNG/JPEG
  • Неограниченное кол-во документов и изображений
  • Техподдержка + обновления (3 мес.)
Приобрести
ХИТ
Работает на:
Тариф "На 1 месяц"
Период действия: 1 месяц
399₽
Полный функционал программы:
  • Массовая обработка Excel → Word и Excel → PNG/JPEG
  • Неограниченное кол-во документов и изображений
  • Техподдержка + обновления (1 мес.)
Приобрести
Работает на:
РобокассаЮ КассаТ Банк
Хотите узнать больше о возможностях SmartDocGen?
Хотите узнать больше о возможностях SmartDocGen?Перейдите на главную страницу и убедитесь сами.
Перейти на главную