在python中,生成HTML文档的最佳方式是什么。我目前手动将所有标签附加到一个巨大的字符串,并将其写入文件。有更优雅的方式吗?
答案 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
这是一个教程,可以帮助您应用语法
答案 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)
还有一个不错的现代替代方法: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>
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()不添加行分隔符。)