我选择了 JF Sebastian 的答案,因为我认为它是最简单的,因此也是最好的,但我正在为不想安装 Beautiful Soup 的任何人添加另一个解决方案。(另外,Beautiful Soup 树构建器将在 html5lib 1.0 中被弃用。)这个解决方案感谢 Amarghosh 的提示;我只是充实了一点。查看 html5lib,我意识到它会原生输出一个 minidom 对象,这意味着我可以使用他的toprettyxml()
. 这是我想出的:
from html5lib import HTMLParser, treebuilders
from cStringIO import StringIO
def tidy_html(text):
"""Returns a well-formatted version of input HTML."""
p = HTMLParser(tree=treebuilders.getTreeBuilder("dom"))
dom_tree = p.parseFragment(text)
# using cStringIO for fast string concatenation
pretty_HTML = StringIO()
node = dom_tree.firstChild
while node:
node_contents = node.toprettyxml(indent=' ')
pretty_HTML.write(node_contents)
node = node.nextSibling
output = pretty_HTML.getvalue()
pretty_HTML.close()
return output
还有一个例子:
>>> text = """<b><i>bold, italic</b></i><div>a div</div>"""
>>> tidy_html(text)
<b>
<i>
bold, italic
</i>
</b>
<div>
a div
</div>
为什么我要遍历树的孩子,而不是直接toprettyxml()
调用dom_tree
?我正在处理的一些 HTML 实际上是 HTML 片段,所以它缺少<head>
and<body>
标记。为了处理这个问题,我使用了这个parseFragment()
方法,这意味着我得到了一个 DocumentFragment 作为回报(而不是一个 Document)。不幸的是,它没有writexml()
方法(toprettyxml()
调用),所以我遍历子节点,它们确实有方法。