在python中生成HTML文档

时间:2011-07-19 14:12:17

标签: python html

在python中,生成HTML文档的最佳方式是什么。我目前手动将所有标签附加到一个巨大的字符串,并将其写入文件。有更优雅的方式吗?

8 个答案:

答案 0 :(得分:43)

我发现yattag是最优雅的做法。

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,附加的好处是你不必关闭标签。

答案 1 :(得分:29)

我建议使用python中可用的众多模板语言中的一种,例如built into Django(您不必使用其余的Django来使用其模板引擎) - 谷歌查询应该给出你有很多其他的替代模板实现。

我发现学习模板库有很多方面的帮助 - 每当你需要生成电子邮件,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://stackoverflow.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)

如果你在磁盘上有模板,那就更简单了 - 查看django 1.7的render_to_string函数,该函数可以从预定义的搜索路径列表中加载来自磁盘的模板,填充来自dictory的数据并渲染为字符串 - 所有功能调用。 (从django 1.8中删除,请参阅Engine.from_string进行类似操作)

答案 2 :(得分:7)

如果您正在构建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"

if sys.version_info < (3, 0, 0):
  # python 2
  ET.ElementTree(html).write(sys.stdout, encoding='utf-8',
                             method='html')
else:
  # python 3
  ET.ElementTree(html).write(sys.stdout, encoding='unicode',
                             method='html')

打印以下内容:

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

答案 3 :(得分:6)

我建议使用xml.dom来执行此操作。

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

阅读本手册页,它提供了构建XML(以及XHTML)的方法。它使所有XML任务变得更加容易,包括添加子节点,文档类型,添加属性,创建文本节点。这应该能够帮助您完成创建HTML的绝大部分工作。

它对于分析和处理现有的xml文档也非常有用。

希望这有帮助

P.S

这是一个教程,可以帮助您应用语法

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

答案 4 :(得分:2)

我正在使用名为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副本。

类似于使用John Smith可选的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>'),
      ]
  ]

答案 5 :(得分:2)

还有一个不错的现代替代方法:airiumhttps://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>

airium的最大优点是-它还有一个反向翻译器,可以从html字符串中构建python代码。如果您想知道如何实现给定的html代码段-转换器会立即为您提供答案。

其存储库包含测试,这些测试包含示例页面,这些示例页面通过tests/documents中的airium自动转换。一个很好的起点(任何现有的教程)-是这样的:tests/documents/w3_architects_example_original.html.py

答案 6 :(得分:-1)

我为 lxml 模块编写了一个简单的包装器(也应该适用于 xml),它为 HTML/XML -esq 文档制作标签。

真的,我喜欢 John Smith 的 answer 格式,但我不想安装 YET ANOTHER MODULE 来完成看起来如此简单的事情。

首先是示例,然后是包装器。

示例

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

答案 7 :(得分:-2)

是的,您正在寻找文件.writelines

序列通常是列表或数组。所以将所有行放入列表或数组中。 并将它们抛给下面的函数。

确保从字符串中删除任何新的行常量只是为了安全

Python Documentation ( search for file.writelines )

file.writelines(序列)     将一系列字符串写入文件。序列可以是产生字符串的任何可迭代对象,通常是字符串列表。没有回报价值。 (该名称旨在匹配readlines(); writelines()不添加行分隔符。)