Генерация HTML-документов в Python

В Python, какой самый элегантный способ создания HTML-документов. В настоящее время я вручную добавляю все теги в гигантскую строку и записываю это в файл. Есть ли более элегантный способ сделать это?

9 ответов

Я считаю, что яттаг - самый элегантный способ сделать это.

from yattag import Doc

doc, tag, text = Doc().tagtext()

with tag('html'):
    with tag('body'):
        with tag('p', id = 'main'):
            text('some text')
        with tag('a', href='/my-url'):
            text('some link')

result = doc.getvalue()

Он читается как HTML, с дополнительным преимуществом, что вам не нужно закрывать теги.

Я бы предложил использовать один из многих языков шаблонов, доступных для python, например, встроенный в Django (вам не нужно использовать остальную часть Django, чтобы использовать его движок шаблонов) - запрос Google должен дать вам множество других альтернатив. Реализация шаблонов.

Я считаю, что изучение библиотеки шаблонов помогает во многих отношениях - когда вам нужно сгенерировать электронное письмо, HTML-страницу, текстовый файл или подобное, вы просто пишете шаблон, загружаете его в свою библиотеку шаблонов, а затем позволяете создавать код шаблона. готовый продукт.

Вот простой код для начала работы:

#!/usr/bin/env python

from django.template import Template, Context
from django.conf import settings
settings.configure() # We have to do this to use django templates standalone - see
# http://stackru.com/questions/98135/how-do-i-use-django-templates-without-the-rest-of-django

# Our template. Could just as easily be stored in a separate file
template = """
<html>
<head>
<title>Template {{ title }}</title>
</head>
<body>
Body with {{ mystring }}.
</body>
</html>
"""

t = Template(template)
c = Context({"title": "title from code",
             "mystring":"string from code"})
print t.render(c)

Еще проще, если у вас есть шаблоны на диске - посмотрите на функцию render_to_string, которая может загружать шаблоны с диска из предварительно определенного списка путей поиска, заполнять данными из диктории и отображать в строку - все в одном вызове функции.

Если вы создаете документы HTML, я настоятельно рекомендую использовать систему шаблонов (например, jinja2), как предлагали другие. Если вам нужна генерация html-битов низкого уровня (возможно, в качестве входных данных для одного из ваших шаблонов), тогда пакет xml.etree является стандартным пакетом python и может хорошо соответствовать всем требованиям.

import sys
from xml.etree import ElementTree as ET

html = ET.Element('html')
body = ET.Element('body')
html.append(body)
div = ET.Element('div', attrib={'class': 'foo'})
body.append(div)
span = ET.Element('span', attrib={'class': 'bar'})
div.append(span)
span.text = "Hello World"


ET.ElementTree(html).write(sys.stdout, encoding='utf8',
                           method='html')

Печатает следующее:

<html><body><div class="foo"><span class="bar">Hello World</span></div></body></html>

Есть и хорошая современная альтернатива: airium: https://pypi.org/project/airium/

from airium import Airium

a = Airium()

a('<!DOCTYPE html>')
with a.html(lang="pl"):
    with a.head():
        a.meta(charset="utf-8")
        a.title(_t="Airium example")

    with a.body():
        with a.h3(id="id23409231", klass='main_header'):
            a("Hello World.")

html = str(a) # casting to string extracts the value

print(html)

Печатает такую ​​строку:

<!DOCTYPE html>
<html lang="pl">
  <head>
    <meta charset="utf-8" />
    <title>Airium example</title>
  </head>
  <body>
    <h3 id="id23409231" class="main_header">
      Hello World.
    </h3>
  </body>
</html>

Самое большое преимущество airiumis - у него также есть обратный переводчик, который строит код python из строки html. Если вам интересно, как реализовать данный html-фрагмент - переводчик сразу даст вам ответ.

Например, его тесты содержат примеры страниц, автоматически переведенных с помощью airium:https://gitlab.com/kamichal/airium/-/tree/master/tests/documents

Я бы порекомендовал использовать xml.dom для этого.

http://docs.python.org/library/xml.dom.html

Прочтите эту страницу руководства, у нее есть методы для создания XML (и, следовательно, XHTML). Это значительно упрощает все задачи XML, включая добавление дочерних узлов, типов документов, добавление атрибутов, создание текстовых узлов. Это должно помочь вам в подавляющем большинстве вещей, которые вы будете делать для создания HTML.

Это также очень полезно для анализа и обработки существующих XML-документов.

Надеюсь это поможет

PS

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

http://www.postneo.com/projects/pyxml/

Я использую фрагмент кода, известный как throw_out_your_templates для некоторых из моих собственных проектов:

https://github.com/tavisrudd/throw_out_your_templates

https://bitbucket.org/tavisrudd/throw-out-your-templates/src

К сожалению, для него нет пакета pypi, и он не является частью какого-либо дистрибутива, поскольку он предназначен только для проверки концепции. Я также не смог найти кого-то, кто взял код и начал поддерживать его как реальный проект. Тем не менее, я думаю, что стоит попробовать, даже если это означает, что вы должны отправить свою собственную копию throw_out_your_templates.py с вашим кодом.

Аналогично предложению использовать yattag Джоном Смитом, необязательно, этот модуль не требует изучения какого-либо языка шаблонов, а также гарантирует, что вы никогда не забудете закрыть теги или заключить в кавычки специальные символы. Все остается написанным на Python. Вот пример того, как его использовать:

html(lang='en')[
  head[title['An example'], meta(charset='UTF-8')],
  body(onload='func_with_esc_args(1, "bar")')[
      div['Escaped chars: ', '< ', u'>', '&'],
      script(type='text/javascript')[
           'var lt_not_escaped = (1 < 2);',
           '\nvar escaped_cdata_close = "]]>";',
           '\nvar unescaped_ampersand = "&";'
          ],
      Comment('''
      not escaped "< & >"
      escaped: "-->"
      '''),
      div['some encoded bytes and the equivalent unicode:',
          '你好', unicode('你好', 'utf-8')],
      safe_unicode('<b>My surrounding b tags are not escaped</b>'),
      ]
  ]

Я пытаюсь сделать более простое решение под названием PyperText.

В котором вы можете делать такие вещи:

      from PyperText.html import Script
from PyperText.htmlButton import Button
#from PyperText.html{WIDGET} import WIDGET; ex from PyperText.htmlEntry import Entry; variations shared in file
myScript=Script("myfile.html")
myButton=Button()
myButton.setText("This is a button")
myScript.addWidget(myButton)
myScript.createAndWrite()

Я написал простую оболочку для lxml модуль (должен нормально работать с xml а также), который создает теги для документов HTML / XML -esq.

На самом деле, мне понравился формат ответа Джона Смита, но я не хотел устанавливать ЕЩЕ ДРУГОЙ МОДУЛЬ для выполнения чего-то, что казалось таким простым.

Сначала пример, потом обертка.

Пример

      from Tag import Tag


with Tag('html') as html:
    with Tag('body'):
        with Tag('div'):
            with Tag('span', attrib={'id': 'foo'}) as span:
                span.text = 'Hello, world!'
            with Tag('span', attrib={'id': 'bar'}) as span:
                span.text = 'This was an example!'

html.write('test_html.html')

Выход:

      <html><body><div><span id="foo">Hello, world!</span><span id="bar">This was an example!</span></div></body></html>

Вывод после ручного форматирования:

      <html>
    <body>
        <div>
            <span id="foo">Hello, world!</span>
            <span id="bar">This was an example!</span>
        </div>
    </body>
</html>

Обертка

      from dataclasses import dataclass, field
from lxml import etree


PARENT_TAG = None


@dataclass
class Tag:
    tag: str
    attrib: dict = field(default_factory=dict)
    parent: object = None
    _text: str = None

    @property
    def text(self):
        return self._text

    @text.setter
    def text(self, value):
        self._text = value
        self.element.text = value

    def __post_init__(self):
        self._make_element()
        self._append_to_parent()

    def write(self, filename):
        etree.ElementTree(self.element).write(filename)

    def _make_element(self):
        self.element = etree.Element(self.tag, attrib=self.attrib)

    def _append_to_parent(self):
        if self.parent is not None:
            self.parent.element.append(self.element)

    def __enter__(self):
        global PARENT_TAG
        if PARENT_TAG is not None:
            self.parent = PARENT_TAG
            self._append_to_parent()
        PARENT_TAG = self
        return self

    def __exit__(self, typ, value, traceback):
        global PARENT_TAG
        if PARENT_TAG is self:
            PARENT_TAG = self.parent

Да, вы ищете файл.writelines

Последовательность обычно представляет собой список или массив. Поэтому поместите все свои строки в список или массив. И бросить их в функцию ниже.

Обязательно удалите все новые строковые константы из ваших строк, чтобы быть в безопасности

Документация по Python (поиск для file.writelines)

file.writelines (sequence) Записать последовательность строк в файл. Последовательность может быть любым итерируемым объектом, создающим строки, обычно списком строк. Нет возвращаемого значения. (Имя предназначено для соответствия readlines(); writelines() не добавляет разделители строк.)

Другие вопросы по тегам