lxml.html を使用してHTMLを生成しています。最終結果を(インデント付きで)HTMLファイルにきれいに印刷したい。それ、どうやったら出来るの?
これは私が今まで試してきたものです(Python and lxml)は比較的新しいです):
import lxml.html as lh
from lxml.html import builder as E
sliderRoot=lh.Element("div", E.CLASS("scroll"), style="overflow-x: hidden; overflow-y: hidden;")
scrollContainer=lh.Element("div", E.CLASS("scrollContainer"), style="width: 4340px;")
sliderRoot.append(scrollContainer)
print lh.tostring(sliderRoot, pretty_print = True, method="html")
ご覧のとおり、私はpretty_print=True
属性。私はそれがインデントされたコードを与えると思ったが、それは本当に助けにはならない。これは出力です:
<div style="overflow-x: hidden; overflow-y: hidden;" class="scroll"><div style="width: 4340px;" class="scrollContainer"></div></div>
最終的に BeautifulSoup を直接使用しました。 lxml.html.soupparser はHTMLの解析に使用します。
BeautifulSoupには、指定されたとおりの処理を行うprettifyメソッドがあります。適切なインデントとすべてでHTMLをきれいにします。
BeautifulSoupはHTMLを修正しないため、壊れたコードは壊れたままです。しかし、この場合、コードはlxmlによって生成されているため、HTMLコードは少なくとも意味的に正しいはずです。
私の質問で与えられた例では、これをしなければなりません:
from BeautifulSoup import BeautifulSoup as bs
root = lh.tostring(sliderRoot) #convert the generated HTML to a string
soup = bs(root) #make BeautifulSoup
prettyHTML = soup.prettify() #prettify the html
私の答えは今は役に立たないかもしれませんが、将来的に他の誰かへの参照として機能するためにここにドロップします。
lxml.html.tostring()
は実際、pretty_print=True
にもかかわらず提供されたHTMLをきれいに出力しません。
ただし、lxml.html
-lxml.etree
の「兄弟」はうまく機能しています。
したがって、次のように使用できます。
from lxml import etree, html
document_root = html.fromstring("<html><body><h1>hello world</h1></body></html>")
print(etree.tostring(document_root, encoding='unicode', pretty_print=True))
出力は次のようになります。
<html>
<body>
<h1>hello world</h1>
</body>
</html>
HTMLをフォーマットされていない文字列として、変数html_string
、次のようにbeautifulsoup4を使用して実行できます。
from bs4 import BeautifulSoup
print(BeautifulSoup(html_string, 'html.parser').prettify())
内部では、lxml
はlibxml2
を使用してツリーをシリアル化して文字列に戻します。タグを閉じた後に改行を追加するかどうかを決定するコードの関連スニペットは次のとおりです。
xmlOutputBufferWriteString(buf, ">");
if ((format) && (!info->isinline) && (cur->next != NULL)) {
if ((cur->next->type != HTML_TEXT_NODE) &&
(cur->next->type != HTML_ENTITY_REF_NODE) &&
(cur->parent != NULL) &&
(cur->parent->name != NULL) &&
(cur->parent->name[0] != 'p')) /* p, pre, param */
xmlOutputBufferWriteString(buf, "\n");
}
return;
そのため、ノードが要素であり、インラインタグではなく、兄弟ノードが後に続く(cur->next != NULL
)であり、p, pre, param
のいずれでもない場合、改行。
依存関係をもう1つ追加しても問題ない場合は、 html5print パッケージを使用できます。他のソリューションに勝る利点は、HTMLドキュメントに埋め込まれたCSSとJavaScriptコードの両方を美しくすることです。
それをインストールするには、次を実行します:
pip install html5print
次に、コマンドとして使用できます。
html5-print ugly.html -o pretty.html
またはPython code:
from html5print import HTMLBeautifier
html = '<title>Page Title</title><p>Some text here</p>'
print(HTMLBeautifier.beautify(html, 4))
BeautifulSoupのprettify
とhtml5printのHTMLBeautifier
ソリューションの両方を試しましたが、HTMLを生成するために yattag を使用しているので、indent
関数を使用する方が適切なようです。 、適切にインデントされた出力を生成します。
from yattag import indent
rawhtml = "String with some HTML code..."
result = indent(
rawhtml,
indentation = ' ',
newline = '\r\n',
indent_text = True
)
print(result)
それを HTML Tidy にパイプするだけではできませんか?シェルから、またはos.system()
を介して。
風変わりなHTMLを気にしない場合(たとえば、Netscpae 2.0を使用するクライアントの大群を完全にサポートする必要があるため、<br>
の代わりに <br />
は必須です)、メソッドをいつでも "xml"に変更できます。これは動作しているようです。これはおそらくlxmlまたはlibxmlのバグですが、その理由はわかりませんでした。
私のコードではなく、どこかで選んだ
def indent(elem, level=0):
i = '\n' + level * ' '
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + ' '
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
indent(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
私はそれを使用します:
indent(page)
tostring(page)