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

问题描述 投票:0回答:10

我正在使用 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>

python html lxml pretty-print
10个回答
134
投票

我最终直接使用了BeautifulSoup。这是 lxml.html.soupparser 用于解析 HTML 的东西。

BeautifulSoup 有一个美化方法,它完全按照它说的做。它用适当的缩进和一切美化 HTML。

BeautifulSoup 不会修复 HTML,因此损坏的代码仍然会损坏。但在这种情况下,由于代码是由 lxml 生成的,因此 HTML 代码至少在语义上应该是正确的。

在我的问题给出的例子中,我将不得不这样做:

from bs4 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

48
投票

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

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>

29
投票

如果将 HTML 存储为未格式化的字符串,在变量

html_string
中,可以使用 beautifulsoup4 完成,如下所示:

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

8
投票

如果再添加一个依赖没有问题,你可以使用 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))

5
投票

我尝试了 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)

4
投票

在幕后,

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
之一那么它将输出一个换行符。


3
投票

你不能把它导入HTML Tidy吗?从外壳或通过

os.system()
.


2
投票

如果您不关心古怪的 HTML(例如,您必须绝对支持那些使用 Netscpae 2.0 的客户端,因此必须使用

<br>
而不是
<br />
),您可以随时将方法更改为“xml ",这似乎有效。这可能是 lxml 或 libxml 中的错误,但我找不到原因。


2
投票

不是我的代码,我在某处捡到的

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)

0
投票

这很粗糙而且不是很健壮,但它会平衡示例 html 字符串,而无需使用任何非标准库

import re
html = """
<A value="X"><B value="X">
<A value="X"><B value="X">
some random text
</B></A><C />
some random text
</B></A><C />
"""
rx_al = r"(<[\/A-Za-z]+[^>]*>)"
rx_op = r"<([A-Za-z]+)[^\/]+>"
rx_cl = r"</([A-Za-z]+)>"
# self-closing not needed
#rx_sc = r"<([A-Za-z]+).* \/>"
matches = re.findall(rx_al, html, flags=re.M)

def lookup_key(match, indent):
  return f"{match[0]}:{indent}"

def balance(nodes):
  builder = []
  indent = 0
  lookup = {}
  for node in nodes:
    is_open = re.match(rx_op, node)
    is_close = re.match(rx_cl, node)
    padl = " " * indent
    if is_open:
      k = lookup_key(is_open, indent)
      lookup[k] = node
      indent += 2
    elif is_close:
      for i in range(0, indent, -2):
        if lookup.pop(lookup_key(is_close, i), None):
          break
      indent -= 2
      padl = padl[:-2]
    builder.append(padl + node)
  return "\n".join(builder)

print(balance(matches))

将产生:

<A value="X">
  <B value="X">
    <A value="X">
      <B value="X">
      </B>
    </A>
    <C />
  </B>
</A>
<C />

© www.soinside.com 2019 - 2024. All rights reserved.