如何使用缩进将 HTML 漂亮地打印到文件中

Posted

技术标签:

【中文标题】如何使用缩进将 HTML 漂亮地打印到文件中【英文标题】:How to Pretty Print HTML to a file, with indentation 【发布时间】:2011-09-03 06:05:59 【问题描述】:

我正在使用lxml.html 生成一些 HTML。我想将我的最终结果漂亮地打印(带有缩进)到一个 html 文件中。我该怎么做?

这是我到目前为止所尝试和得到的

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>

【问题讨论】:

【参考方案1】:

我最终直接使用了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

【讨论】:

谢谢,但值得一提的是,如果对某人很重要,嵌入到 html 的js 不会美化。 在版本 4 中将第一行更改为 from bs4 import BeautifulSoup as bs 如果您只想从字符串中美化 html,请参阅下面 AlexG 的回答。 小心prettify,因为它改变了文档语义:“由于它添加了空格(以换行符的形式),prettify() 改变了 HTML 文档的含义,不应该用于重新格式化一个。prettify() 的目标是帮助您直观地了解您使用的文档的结构。"【参考方案2】:

我尝试了 BeautifulSoup 的 prettify 和 html5print 的 HTMLBeautifier 解决方案,但由于我使用 yattag 生成 HTML,因此使用它的 indent 函数似乎更合适,它可以产生很好的缩进输出。

from yattag import indent

rawhtml = "String with some HTML code..."

result = indent(
    rawhtml,
    indentation = '    ',
    newline = '\r\n',
    indent_text = True
)

print(result)

【讨论】:

【参考方案3】:

如果再添加一个依赖不成问题,您可以使用html5print 包。与其他解决方案相比,它的优势在于它还美化了嵌入在 HTML 文档中的 CSS 和 javascript 代码。

要安装它,请执行:

pip install html5print

然后,您可以将其用作命令:

html5-print ugly.html -o pretty.html

或作为 Python 代码:

from html5print import HTMLBeautifier
html = '<title>Page Title</title><p>Some text here</p>'
print(HTMLBeautifier.beautify(html, 4))

【讨论】:

这会安装其他几个依赖项,包括 beautifulsoup4【参考方案4】:

如果您将 HTML 存储为未格式化的字符串,在变量 html_string 中,可以使用 beautifulsoup4 来完成,如下所示:

from bs4 import BeautifulSoup
print(BeautifulSoup(html_string, 'html.parser').prettify())

【讨论】:

【参考方案5】:

虽然我的回答现在可能没有帮助,但我将其放在这里以作为将来其他人的参考。

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>

【讨论】:

pretty_print 标志仅在使用method='xml' 调用etree.tostring 时有效,这是默认设置。所以,我们在这里处理 XHTML。 这是一个很好的答案,因为它不使用任何外部依赖项。但是,如果包含 HTML 的字符串有回车,etree.tostring 什么都没有,并且至少在 Python 2.7.10 上返回其输入,不变......一旦你知道,替换回车是一件简单的事情,但是你不知道会浪费很多时间。 这很棒,因为它只提供了选项卡的解决方案。这不会以其他方式更改 HTML,例如 BeautifulSoup 解决方案。 不!这就是为什么。 etree.tostring 会将 "" 缩短为 "",这是不允许的。【参考方案6】:

在后台,lxml 使用libxml2 将树序列化回字符串。下面是相关的sn-p代码,判断关闭标签后是否追加换行符:

    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-&gt;next != NULL)并且不是p, pre, param之一,那么它将输出一个换行符.

【讨论】:

【参考方案7】:

不是我的代码,是我在某处挑选的

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)

【讨论】:

【参考方案8】:

你不能直接把它输入HTML Tidy吗?从 shell 或通过os.system()

【讨论】:

我最初想使用 HTML Tidy,但我的代码有点古怪,而整洁最终却对它造成了破坏。决定改用 BeautifulSoup。像魅力一样工作。 HTML Tidy 更正您的 HTML 可以break things。如果您忘记了 HTML Tidy 正在处理结果(我知道我在说什么),那么很难找到此类错误... 比这里的 2011 年 cmets 更近,请参阅这个 2018 年问题的答案:***.com/questions/50380799/…。 “该库已损坏和/或不适用于 python 3.5。”可能会节省一些时间...【参考方案9】:

如果您不关心古怪的 HTML(例如,您必须绝对支持那些使用 Netscpae 2.0 的客户端,因此必须使用 &lt;br&gt; 而不是 &lt;br /&gt;),您可以随时将您的方法更改为“xml”,这似乎工作。这可能是lxml或libxml中的一个错误,但我找不到它的原因。

【讨论】:

设置方法为xml时,如果标签没有子元素,则不生成结束标签。例如,在有问题的示例中,内部 div 将没有结束标记。我真的不知道为什么。我最终使用 BeautifulSoup 来获得正确的输出。

以上是关于如何使用缩进将 HTML 漂亮地打印到文件中的主要内容,如果未能解决你的问题,请参考以下文章

使用 JavaScript 漂亮地打印 JSON

如何漂亮地打印嵌套字典?

使用 Python 将 JSON 数据漂亮地打印到文件中

如何让 Python 的 ElementTree 漂亮地打印到 XML 文件?

如何有效地漂亮打印 JSON 对象列表? [复制]

缩进,漂亮的打印代码,包括 Django 模板标签、HTML、CSS 和 JavaScript [关闭]