Русский
Русский
English
Статистика
Реклама

Recovery mode HTML PDF Python

Наверняка не очень редко возникает задача печати HTML-документов с какого-то сервера в точности как задумано автором этого сервера. Делать это лучше всего не в надежде на браузер клиента, а на стороне сервера. А если на сервере крутится нечто на питоне (Django/Flask/тысячи их), то хорошо бы оценить во что это обойдется.

Для тестов выбирались такие библиотеки, чтобы как минимум были в виде пакетов в официальных репо RH-based дистрибутивов или же - в крайнем случае - можно было таковые собрать. И чтобы без долгих танцев с бубном.
В macOS всё ставилось с помощью homebrew и pip3, в Fedora - из стандартного репо (искл. xhtml2pdf - этого в репах нет, но при должной усидчивости за пару часов можно собрать вполне себе цивильный rpm).

Дано:

После тщательного отбора кандидатов накопилось аж 3:

  • python-pdfkit - адаптер к вызову бинарника wkhtmltopdf.

  • weasyprint - прокладка между html5lib и reportlab.

  • xhtml2pdf - примерно то же самое, что и weasyprint, но со своими тараканами особенностями. В таблице указано как "Pisa" (основной модуль).

Платформ для тестирования набралось под руками тоже 3 (все x64):

  • MacBook - Apple MacBookPro9.2 (13" mid 2012, i5-3210M (2.5GHz)), HDD, macOS 10.15 "Catalina", Python 3.9 (brew)

  • LinBook (так это назовем) - тот же самый макбук, но с Fedora 33, Python 3.9

  • DeskTop - Intel G3450 (3.4GHz), HDD, Fedora 33, Python 3.9

Документов для тестов - 3 (все - на одну страничку каждый):

  • ПД4 - квитанция на оплату налогов и сборов в Сбер (форма ПД-4сб). HTML ручной работы, максимально соответствующий стандартам. Требования к точности передачи задумки автора в печати довольно высокие.

  • Инструкция - чей-то документ с заголовком, комментариями, табличками и местом для подписи. Получен из .doc экспортом из Word 2007. HTML не так, чтобы очень тяжелый, но на тяп-ляп. То есть как оно и будет в жизни. Требования к точности - никакие.

  • Р21001 - последний листик (стр.5Б) формы Р21001 - с якорями для сканера, буквами в квадратиках и всем остальным, что мы так любим в документах для налоговой. Экспорт из Excel 2007, IE6-совместимо. Получилось 2 МБ формально правильного HTML, но совершенно фееричной разметки, то есть достаточно тяжелого для парсера-генератора. Требования к точности очень высокие.

Решение:

Код на коленке
#!/usr/bin/env python3# -*- coding: utf-8 -*-"""Benchmark of html-to-pdf converters.(c) @justhabrauser, GPLv3."""# 1. systemimport osimport sysfrom time import time# 2. 3rdfrom pdfkit import from_string          # https://github.com/JazzCore/python-pdfkitfrom weasyprint import HTML             # https://github.com/Kozea/WeasyPrintfrom xhtml2pdf.pisa import CreatePDF    # https://github.com/xhtml2pdf/xhtml2pdfdef __pdfkit(html: str) -> bytes:    return from_string(html, False, options={'quiet': ''})def __weasy(html: str) -> bytes:    return HTML(string=html).write_pdf()def __pisa(html: str) -> bytes:    pdf = CreatePDF(html)    if not pdf.err:        pdf.dest.seek(0)        return pdf.dest.read()def main(indir: str, outdir: str, count: int) -> None:    # 1. Load all htmls    modules = (__pdfkit, __weasy, __pisa)    html_list = list()      # (filename, content)[]    dir_list = os.listdir(indir)    dir_list.sort()    for i, fn in enumerate(dir_list):        fpath = os.path.join(indir, fn)        if os.path.isfile(fpath) and fpath.endswith(".html"):            print("Load '{}'".format(fn), file=sys.stderr)            with open(fpath, "rt") as i_f:                html = i_f.read()                html_list.append(html)                # 2. write results (and warm up)                for j, m in enumerate(modules):                    with open(os.path.join(outdir, "%d_%d.pdf" % (i, j)), "wb") as o_f:                        o_f.write(m(html))    # 2. for C times x I pages x J engines:    print("Count\tPage\tEngine\tTime\n=====\t====\t======\t====")    for c in range(count):                   # count        for i, h in enumerate(html_list):    # html page            for j, m in enumerate(modules):  # engine                t0 = time()                m(h)                t1 = time()                print("{}\t{}\t{}\t{}".format(c, i, j, t1-t0))if __name__ == '__main__':    if len(sys.argv) != 3:        print("Usage: {} <dir_with_htmls> <output_dir_for_pdfs>".format(sys.argv[0]), file=sys.stderr)    elif not os.path.isdir(sys.argv[1]):        print("Input '{}' is not dir or not exists.".format(sys.argv[1]), file=sys.stderr)    elif not os.path.isdir(sys.argv[2]):        print("Output '{}' is not dir or not exists.".format(sys.argv[2]), file=sys.stderr)    else:        main(sys.argv[1], sys.argv[2], 5)

Среднее время обработки каждого документа (в разрезе документов, библиотек и платформ (D=DeskTop, L=LinBook, M=MacBook)), сек.:

Lib

ПД4

Смета

Р21001

D

L

M

D

L

M

D

L

M

Pdfkit

0,36

0,44

1,49

0,36

0,44

1,23

1,3

1,9

6,9

Weasy

0,36

0,47

0,60

0,27

0,36

0,65

26,1

34,8

54,7

Pisa

0,12

0,17

0,28

0,29

0,41

0,68

20,4

27,3

42,2

Выводы: таракан без ног не слышит

Общий вывод - счастья нет. То есть я не смог ни одного кандидата однозначно выгнать на мороз или наградить золотой медалью. В среднем по больнице видно, что pdfkit дольше запрягает, но потом быстрее едет, но это и без тестов логично (хотя разница все-равно впечатляет). Ну а так каждый может оценить цифры, протестировать самостоятельно и сделать свои выводы. Я могу только привести свои личные впечатления:

  • pdfkit. Все-таки это не чистокровный питон и даже не обертка C-либы, что нарушает внутреннюю гармонию и бесит перфекционизм. Радует высокое качество полученного PDF, максимально точная передача задумки (реально WYSIWYG), максимальная скорость на тяжелых документах. Не радует неторопливость на мелких задачах и почти полная неуправляемость.

  • weasyprint. Бедненько - но чистенько. Всеядное, приемлемая (а иногда и неплохая) скорость, достаточно предсказуемый результат. Но без наворотов и без рекордов.

  • xhtml2pdf. Вредное. HTML должен не просто идеально соответствовать стандартам, он должен еще понравиться этой либе, иначе "инжалид дежице". Отдельно идут упражнения с кириллицей (кстати, я тестировал без этих упражнений (лениво), то есть не совсем корректно) и фееричность получаемого результата. За это там куча наворотов и в среднем хорошая скорость работы (как для питона).

Отдельно стоят вопросы управления разрывами страниц, нумерация страниц, хорошо бы еще попробовать iText7 (но это вязать python с java, что из категории секаса переводит вопрос в категорию прона), wkhtmltopdf-static и иные окружения. Но я хотел просто быстро оценить порядок скорости на целевой лично для меня платформе (RHEL8+).

Источник: habr.com
К списку статей
Опубликовано: 27.02.2021 12:14:40
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Python

Html

Pdf

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru