html5tagger
快速上手#
安装:
pip install html5tagger
html5tagger
提供了两个 HTML 生成的起点:E
用于创建空的构建器来生成 HTML 片段,或者 Document
用于生成带有 DOCTYPE
声明的完整 HTML 文档。两者都会产生 Builder
对象,以防你需要它进行类型注解。
通过点表示法创建片段并添加标签:
E.p("Powered by:").br.a(href="...")("html5tagger")
生成:
<p>Powered by:<br><a href="...">html5tagger</a>
html5tagger
简单示例#
from html5tagger import Document, E
创建 document
:
doc = Document(
E.TitleText_, # 第一个参数是用于 `<title>`,添加变量TitleText。
lang="en", # 关键字参数用于 `<html>` 属性。
# 只需列出你需要的资源,无需记住 link/script标签。
_urls=[ "style.css", "favicon.png", "manifest.json" ]
)
大写名称是模板变量。你可以在之后修改它们:
print(doc.Head_)
<!DOCTYPE html><html lang=en><meta charset="utf-8"><title></title><link href="style.css" rel=stylesheet><link href="favicon.png" rel=icon type="image/png"><link href="manifest.json" rel=manifest>
进入 <h1>
并同时更新 <title>
。
print(doc.h1.TitleText_("Demo") )
<!DOCTYPE html><html lang=en><meta charset="utf-8"><title>Demo</title><link href="style.css" rel=stylesheet><link href="favicon.png" rel=icon type="image/png"><link href="manifest.json" rel=manifest><h1>Demo</h1>
这一直是 DOM 和其他此类生成器的难题:
doc.p("A paragraph with ").a("a link", href="/files")(" and ").em("formatting")
对于复杂的嵌套(通常不需要)使用 with
。
with doc.table(id="data"):
doc.tr.th("First").th("Second").th("Third")
doc.TableRows_
在模板变量中添加一些东西:
print(doc.Head._script("console.log('</script> escaping is weird')"))
<script>console.log('<\/script> escaping is weird')</script>
table = doc.TableRows
for row in range(10):
table.tr
for col in range(3):
table.td(row * col)
doc
或者删除我们刚刚添加的表格数据:
doc.TableRows = None
doc
你可以使用 str(doc)
来获取 HTML 代码,直接使用 doc
通常也能达到预期效果(例如提供 HTML 响应)。Jupyter Notebooks 将其渲染为 HTML。对于调试,使用 repr(doc)
,其中模板变量是可见的:
print(doc)
<!DOCTYPE html><html lang=en><meta charset="utf-8"><title>Demo</title><link href="style.css" rel=stylesheet><link href="favicon.png" rel=icon type="image/png"><link href="manifest.json" rel=manifest><script>console.log('<\/script> escaping is weird')</script><h1>Demo</h1><p>A paragraph with <a href="/files">a link</a> and <em>formatting</em><table id=data><tr><th>First<th>Second<th>Third</table>
实际的 HTML 输出是类似的。文档中没有添加任何空白,除非内容包含换行符,否则都在同一行。您可能会注意到,body
和其他熟悉的标签都不见了,转义也很少。这就是HTML5:文档符合标准,且少了很多冗余。
html5tagger
模板#
使用模板变量构建一次文档,在渲染时只更新动态部分,以获得更快的性能。通过 doc.TitleText
访问模板变量,并在标签名后的括号中添加内容。标签名末尾的下划线表示该标签被添加到文档中,并且可以在括号中有内容,但同一行上任何进一步的标签都会进入原始文档,而不是模板。
html5tagger
嵌套#
在 HTML5 中,像 <p>
这样的元素不需要任何闭合标签,因此我们可以不断添加内容而不必担心何时应该关闭。对于可选或禁止使用闭合标签的元素,此模块不使用闭合标签。
当您向一个元素添加内容或添加另一个标签时,该元素会自动闭合。仅仅设置属性并不会关闭一个元素。如果后续的任何内容都不应该在它内部,则可以使用(None
)来关闭空元素,例如 doc.script(None, src="...")
。
对于像 <table>
和 <ul>
这样的元素,您可以使用 with
块,传递子片段参数,或添加一个模板变量。与添加另一个标签不同,添加模板不会关闭其前面的标签,而是将变量放在任何打开的元素内部。
with doc.ul: # Nest using with
doc.li("Write HTML in Python")
doc.li("Simple syntax").ul(id="inner").InnerList_ # Nest using template
doc.li("No need for brackets or closing tags")
doc.ul(E.li("Easy").li("Peasy")) # Nest using (...)
html5tagger
Escaping#
所有内容和属性都会自动转义。例如,我们可以将整个文档放入 iframe
的 srcdoc
属性中,这里只应用了最少但必要的转义。使用自定义方法 _script
、_style
和 _comment
进行相应的内联格式,以遵循它们的自定义转义规则。
doc = Document("Escaping & Context")
doc._style('h1::after {content: "</Style>"}').h1("<Escape>")
doc._comment("All-->OK")
doc.iframe(srcdoc=Document().p("& is used for &"))
<Escape>
名称混淆和布尔属性#
名称末尾的下划线会被忽略,因此尽管 class_
和 for_
等属性是 Python 中的保留字,也可以使用。其他下划线会转换为连字符。
备注
上述仅适用于 HTML 元素和属性,但模板占位符仅使用末尾的下划线来表示它应该放在文档上,而不是被获取以供使用。
布尔值会转换为简短的属性。
E.input(type="checkbox", id="somebox", checked=True).label(for_="somebox", aria_role="img")("🥳")
预格式化的 HTML#
所有内容都会自动转义,除非它提供了 __html__
方法,该方法返回 HTML 格式的字符串。同样,此模块的构建器对象也暴露了 __html__
和 _repr_html_
访问器,允许它们在 Jupyter Notebooks 和遵循此约定的各种其他系统中渲染为 HTML。
任何预格式化的 HTML 都可以用 html5tagger.HTML(string_of_html)
包裹,以避免在包含在文档中时被转义,因为 HTML 类有这些访问器。
小技巧
不要将 HTML()
用于文本,特别是不要用于用户发送的可能包含您不打算作为 HTML 执行的 HTML 的消息。
html5tagger
性能#
%timeit str(Document("benchmarking", lang="en", _urls=("foo.js", "bar.js")))
24.6 μs ± 38.8 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
Jinja2 从内存模板渲染类似的文档大约需要 10 微秒,但它不需要格式化任何 HTML。当模板与 html5tagger
类似地使用时,渲染时间降至约 4 微秒。
在上面的基准测试中,html5tagger
从头开始创建整个文档,一次一个元素和一个属性。除非您正在动态创建非常大的文档,否则这应该足够快了。