JF Sebastian の回答を選択したのは、それが最も単純で最良だと思うからですが、Beautiful Soup をインストールしたくない人のために別のソリューションを追加しています。(また、Beautiful Soup ツリー ビルダーはhtml5lib 1.0 で廃止される予定です。) この解決策は、Amargosh のヒントのおかげです。少しだけ肉付けしました。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>
および<body>
タグがありません。これを処理するために、parseFragment()
メソッドを使用しました。つまり、(Document ではなく) DocumentFragment を返します。残念ながら、writexml()
メソッド (toprettyxml()
呼び出す) がないため、メソッドを持つ子ノードを反復処理します。