lxml 删除 <head> 中的空格和换行符

6 投票
2 回答
4804 浏览
提问于 2025-04-16 20:13

这个小程序:

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>

在头部的空格和换行被去掉了。即使我们把这两个 <link> 元素放在 <body> 中也是如此。看起来在头部元素之间的空白文本节点(\s*)被删除了。

我该如何保留 <link> 之间的空格和换行呢?(我希望输出和输入完全一样)

2 个回答

2

对我来说

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

我不能确定为什么会有差异,但我建议把参数 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 网站上的 教程。我很想看到一些更好的资源。我自己也是新手,任何新鲜的和 好的 阅读材料都欢迎。

更新

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

sed 也可以做到这一点

sed -i '1,2d;' input.html; sed -i '1 i\<html><head>' input.html

这段代码运行了两个 sed 操作。第一个是删除前两行,第二个是在第一行插入 <html><head>

更新 #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>
1

最后,我使用了html5lib来解析HTML,并生成了一个类似于lxml的树形结构。

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

撰写回答