Полное руководство по конвертации HTML и XML в PDF

Иван Корнев·26.05.2026·5 мин

Конвертация веб-контента в PDF необходима для создания отчетов, счетов, архивов и документов, не зависящих от браузера. Для HTML-страниц наиболее эффективны headless-браузеры (Chrome/Puppeteer), а для XML-данных — преобразование через XSL-FO или промежуточную HTML-генерацию. Выбор инструмента зависит от сложности верстки и требований к точности отображения.

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

Краткий ответ: Если нужно быстро сохранить одну страницу — используйте «Печать в PDF» в браузере. Для автоматизации и массового создания документов из HTML выбирайте Puppeteer или Playwright. Для строгой типографики из XML-данных используйте связку XSL-FO + Apache FOP.

Зачем конвертировать веб-контент в PDF

PDF остается стандартом де-факто для документооборота благодаря своей неизменности. Основные сценарии использования:

  • Архивация и юридическая сила: Фиксация состояния веб-страницы или транзакции на конкретный момент времени.
  • Офлайн-доступ: Пользователи могут читать материалы без интернета, сохраняя оригинальное форматирование.
  • Брендирование: Добавление логотипов, колонтитулов и фирменных шрифтов, которые сложно реализовать в обычном HTML-просмотре.
  • Унификация отчетности: Преобразование разрозненных данных (из API, баз данных в формате XML/JSON) в единый читаемый формат.

Методы конвертации: от простых к сложным

Выбор технологии зависит от источника данных (HTML или XML) и объема задач.

1. Браузерная печать (Ручной режим)

Самый простой способ для единичных задач.

  • Как работает: Ctrl+P (или Cmd+P) → «Сохранить как PDF».
  • Плюсы: Не требует установки ПО, визуальный контроль (WYSIWYG).
  • Минусы: Невозможно автоматизировать, часто ломается верстка сложных страниц, нет контроля над разрывами страниц.

2. Headless-браузеры (HTML → PDF)

Золотой стандарт для современной веб-разработки.

  • Инструменты: Puppeteer, Playwright, Selenium.
  • Как работает: Запускается скрытый экземпляр Chrome/Chromium, который рендерит страницу так же, как обычный браузер, и экспортирует её в PDF.
  • Плюсы: Полная поддержка современного CSS (Flexbox, Grid), JavaScript, веб-шрифтов. Высокая точность воспроизведения.
  • Минусы: Требует ресурсов сервера (CPU/RAM), сложнее в настройке окружения.

3. Специализированные движки (HTML → PDF)

Легковесные альтернативы браузерам.

  • Инструменты: wkhtmltopdf (устаревает, но популярен), WeasyPrint (Python), PrinceXML (коммерческий).
  • Плюсы: Быстрее headless-браузеров, проще в интеграции. WeasyPrint отлично работает с CSS Paged Media.
  • Минусы: Ограниченная поддержка JS и новейших CSS-свойств. wkhtmltopdf базируется на старом WebKit.

4. Конвертация XML данных (XML → FO → PDF)

Классический подход для корпоративного документооборота.

  • Инструменты: Apache FOP, RenderX XEP.
  • Как работает: XML-данные трансформируются с помощью XSLT в формат XSL-FO (Formatting Objects), который описывает точное расположение элементов на странице. Затем FO-процессор генерирует PDF.
  • Плюсы: Идеальный контроль над типографикой, разрывами страниц, нумерацией. Независимость от веб-технологий.
  • Минусы: Высокий порог входа (сложный синтаксис XSL-FO), трудно поддерживать адаптивность.

Совет: Если у вас есть данные в XML, но команда знает только HTML/CSS, конвертируйте XML в HTML-шаблон на бэкенде, а затем используйте Headless-браузер для генерации PDF. Это быстрее, чем изучать XSL-FO.

Сравнение инструментов

ИнструментИсточникСложность настройкиКачество CSS/JSРекомендация
Puppeteer/PlaywrightHTMLСредняяОтличноеДля современных веб-приложений и SPA
WeasyPrintHTML/CSSНизкаяХорошее (без JS)Для Python-проектов и статических отчетов
wkhtmltopdfHTMLНизкаяСреднее (старый CSS)Для легаси-систем и простых страниц
Apache FOPXML (XSL-FO)ВысокаяТипографскоеДля строгих финансовых/юридических документов
PrinceXMLHTML/XMLСредняяОтличноеКогда нужен идеальный PDF и есть бюджет

Пошаговая реализация

Сценарий 1: Автоматическая генерация из HTML (Node.js + Puppeteer)

Этот метод подходит для генерации счетов, билетов или статей.

  1. Установите Puppeteer: npm install puppeteer.
  2. Создайте скрипт генерации:
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  // Переходим на страницу или загружаем HTML-строку
  await page.goto('https://example.com/invoice/123', { waitUntil: 'networkidle0' });
  
  // Генерируем PDF
  await page.pdf({
    path: 'invoice.pdf',
    format: 'A4',
    printBackground: true, // Важно для цветов фона
    margin: { top: '20mm', right: '20mm', bottom: '20mm', left: '20mm' }
  });

  await browser.close();
})();

Сценарий 2: Конвертация XML через промежуточный HTML (Python)

Если данные приходят в XML, проще превратить их в HTML, чем писать XSL-FO.

  1. Используйте шаблонизатор (Jinja2, Mako) для создания HTML из XML-данных.
  2. Примените CSS для печати (@media print).
  3. Сконвертируйте HTML в PDF через WeasyPrint или Playwright.

Пример CSS для управления разрывами страниц:

@media print {
  .page-break { page-break-after: always; }
  h1, h2 { page-break-after: avoid; } /* Заголовки не должны оставаться внизу страницы */
  table { page-break-inside: auto; }
  tr { page-break-inside: avoid; } /* Строки таблицы не должны разрываться */
}

Частые ошибки и как их избежать

  1. Обрезанный контент: Элементы с position: fixed или absolute могут выпадать из потока печати.
    • Решение: Используйте position: relative для основных контейнеров или задавайте явные размеры в @page.
  2. Проблемы со шрифтами: Веб-шрифты могут не загрузиться вовремя при генерации.
    • Решение: Встраивайте шрифты в base64 или убедитесь, что скрипт ждет полной загрузки ресурсов (waitUntil: 'networkidle0').
  3. Разрыв таблиц: Длинные таблицы могут разрываться посередине строки.
    • Решение: Добавьте CSS-свойство break-inside: avoid для строк таблицы (<tr>).
  4. Фоновые цвета не печатаются: Браузеры по умолчанию убирают фон для экономии чернил.
    • Решение: Включите опцию printBackground: true в API или поставьте галочку «Фоновая графика» в диалоге печати браузера.

Внимание: Не полагайтесь на JavaScript-анимации при генерации PDF. Headless-браузеры могут сделать скриншот до завершения анимации, что приведет к пустым блокам. Отключайте анимации через CSS для режима печати.

FAQ

В чем разница между wkhtmltopdf и Puppeteer? wkhtmltopdf использует старый движок WebKit, который плохо поддерживает современный CSS (Flexbox/Grid) и JavaScript. Puppeteer использует актуальный Chrome, обеспечивая точное соответствие тому, что видит пользователь в браузере, но потребляет больше памяти.

Можно ли конвертировать XML напрямую в PDF без HTML? Да, с помощью стандарта XSL-FO и процессоров вроде Apache FOP. Это дает лучший контроль над макетом страницы, но требует изучения сложного синтаксиса FO. Для большинства веб-задач проще конвертировать XML → HTML → PDF.

Как добавить нумерацию страниц в PDF? В CSS для печати используйте псевдоэлементы @page:

@page {
  @bottom-center {
    content: counter(page);
  }
}

Поддержка этого свойства варьируется: отлично работает в WeasyPrint и PrinceXML, ограничена в Chrome/Puppeteer (там чаще используют колонтитулы через HTML-структуру).

Безопасна ли конвертация внешних URL? При конвертации внешних страниц есть риск XSS или загрузки вредоносных скриптов. Всегда запускайте браузер в изолированном окружении (sandbox), отключайте плагины и ограничивайте доступ к файловой системе.