【问题标题】:lxml removes spaces and line breaks in <head>lxml 删除 <head> 中的空格和换行符
【发布时间】:2011-09-22 02:22:29
【问题描述】:

这个小程序:

from lxml.html import tostring, fromstring
e = fromstring('''
<html><head>
        <link href="/comments.css" rel="stylesheet" type="text/css">
        <link href="/index.css" rel="stylesheet" type="text/css">
    </head>
    <body>
        <span></span>
        <span></span>
    </body>
</html>''')

print (tostring(e, encoding=str)) #unicode on python 2

将打印:

<html><head><link href="/comments.css" rel="stylesheet" type="text/css"><link
href="/index.css" rel="stylesheet" type="text/css"></head><body>
        <span></span>
        <span></span>
    </body></html>

删除了头部的空格和换行符。 即使我们将两个 元素放在

中也会发生这种情况。 似乎删除了 head 元素之间的空白文本节点 (\s*)。

如何在 之间保留空格和换行符? (我希望输出与输入完全相同)

【问题讨论】:

  • lxml 用于解析和创建 XML 和 HTML。保证输出的内容具有正确的语法并且可以使用其他工具等进行解析。不能保证它会保留格式,因为这不是 lxml 的目的。如果您想在保留 HTML 格式的同时修改 HTML(为什么要这样做?),那么 lxml 是错误的工具。
  • 尽管您可以使用不同的解析器或标记器。但这不值得付出努力。解释为什么你需要保留空白。通常你不会。
  • 输入由用户给出,我使用 lxml 来检查和清理语法。如果输入没有错误,我想给用户同样的输入。
  • 那么如果没有错误,返回原件? :-) 您可能想研究 htmltidy 或其他已经执行此操作的工具。我相信 BeautifulSoup 会保留空白,但 Python 3 的支持还不是很好。
  • BeautifulSoup(3.1.0.1,与 python 3 兼容的最新版本)不保留空格!

标签: python python-3.x html-parsing lxml


【解决方案1】:

对我来说

print (tostring(e, encoding=str))

返回

>>> print (tostring(e, encoding=str))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/lxml/html/__init__.py", line 1493, in tostring
    encoding=encoding)
  File "lxml.etree.pyx", line 2836, in lxml.etree.tostring (src/lxml/lxml.etree.c:53416)
TypeError: descriptor 'upper' of 'str' object needs an argument

我无法与 descrepencey 说话,但我建议将参数 pretty_print 设置为 true

>>> etree.tostring(e, pretty_print=True)
'<html>\n  <head>\n    <link href="/comments.css" rel="stylesheet" type="text/css"/>\n    <link href="/index.css" rel="stylesheet" type="text/css"/>\n  </head>\n  <body>\n        <span/>\n        <span/>\n    </body>\n</html>\n'

你需要导入 etree from lxml import etree

当输出到输出文件时,空格和换行符将被保留。还有print

>>> print(etree.tostring(e, pretty_print=True))
<html>
  <head>
    <link href="/comments.css" rel="stylesheet" type="text/css"/>
    <link href="/index.css" rel="stylesheet" type="text/css"/>
  </head>
  <body>
        <span/>
        <span/>
    </body>
</html>

我确定您已经查看了API,但如果您还没有查看tostring() 的信息,请参阅此处。 假设您在 lxml 网站上看到了tutorial 也是安全的。我很想看到更多“好”的资源。我自己是lxml 的新手,欢迎阅读任何新的和好的内容。

已更新

你说如果你找不到好的 python 解决方案你会考虑sed

这应该通过sed来完成

sed -i '1,2d;' input.html; sed -i '1 i\&lt;html&gt;&lt;head&gt;' input.html

这正在运行两个sed 程序。第一个删除前 2 行。第二个在第一行插入&lt;html&gt;&lt;head&gt;

更新 #2

我应该多考虑一下。你可以用python做到这一点

    >>> import re
    >>> newString = re.sub('\n  ', '', etree.tostring(e,encoding=unicode,pretty_print=True), count=1)
    >>> print(newString)
      <html><head>
            <link href="/comments.css" rel="stylesheet" type="text/css"/>
            <link href="/index.css" rel="stylesheet" type="text/css"/>
         </head>
         <body>
           <span/>
           <span/>
        </body>
   </html>

【讨论】:

  • 我使用 python 3,而 python 2 使用 unicode。另外我猜这个例外是因为旧版本的lxml。看来您是从包管理器安装 lxml 而不是使用 easy_install。
  • pretty_print 重新排列元素!我想保留空间,但不美化。事实上,我想从用户那里得到输入,而不是用 from_string 和 to_string 来改变它。
  • 啊,python3 可以解释语法上的小分歧。我仍然推荐pretty_print=True,从我的输出来看,它会按照您提出的问题保留空格和换行符。也许使用pretty_print=True 更新您的问题,它的输出,并将其与您想要的输出进行对比。因为,我不太确定你现在在问什么。注意,请使用etree.tostring
  • 查看问题的编辑版本。我希望输出与输入完全相同。 pretty_print=True 在 和 之间添加一个 \n。
  • 这实际上不会保留格式,它只会重新创建看起来像本示例的内容......
【解决方案2】:

最后,我用html5lib解析html并用它生成lxml like tree。

parser = html5lib.HTMLParser(tree=html5lib.getTreeBuilder("lxml"), namespaceHTMLElements=False)

【讨论】:

  • 更新:现在已修复(使用 lxml 3.4.2)
猜你喜欢
  • 1970-01-01
  • 2015-11-09
  • 1970-01-01
  • 1970-01-01
  • 2013-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多