为什么 lxml.html 有时会 swallow/remove 空白而不是保留它?

Why does lxml.html sometimes swallow/remove whitespace instead of preserving it?

鉴于以下代码,人们可能会合理地期望输入 lxml 的几乎完全相同的 HTML 字符串会被吐出。

from lxml import html

HTML_TEST_STRING = r"""
<pre>
<em>abc</em>

<em>def</em>

<sub>ghi</sub>

<sub>jkl</sub>

<em>mno</em>

<em>pqr</em>

</pre>
"""

parser = html.HTMLParser( remove_blank_text=False )
doc = html.fromstring( HTML_TEST_STRING, parser=parser )
print( html_out_string )

相反,即使所有内容都包含在 <pre> 预格式化代码块中,并且 remove_blank_text 标志设置为 False 它仅尊重某些 的内容 保留了空白,但神秘的是 没有 的内容的其他部分。请参阅下面上面代码的意外输出:

<pre>
<em>abc</em>

<em>def</em>

<sub>ghi</sub><sub>jkl</sub><em>mno</em>

<em>pqr</em>

</pre>

具体来说,每当 lxml 遇到 <sub> 标签时,它就会崩溃并丢失 "tail" 文本内容 紧随 sub 元素(即使那个“sub 元素”可以说甚至不是一个元素——因为它被包裹在一个 pre 元素 中)。

这种奇怪行为最有可能的催化剂是,像我一样,您正在使用 Windows 并使用 Python 版本,而 lxml 没有为其发布二进制包。

在这种情况下,one portion of the lxml website points you to the official unofficial Windows binaries for libxml2 这样您 [可能通过 pip 安装脚本] 就可以构建一个支持 您的 Python 的新 lxml 二进制文件版本。然而,问题是 它链接你的二进制文件至少有 4 年历史 并且包含你正在 运行 遇到的错误。

解决此问题的最简单方法是下载并安装实际为 OS/Python 变体构建的 lxml Christoph Gohlke's unofficial binary archive(所谓的 "wheel")。 (lxml 网站的另一部分也推荐这个,但如果你像我一样,你忽略了那个路径,想要 运行 尽可能少的非官方​​二进制代码。)

(例如pip3 install --upgrade lxml-3.5.0-cp35-none-win32.whl

Golke 的包是使用较新版本的 libxml2 构建的,它显然已经修复了该错误,因此如果以上一切正常,您现在就可以停止浪费生命中的几个小时 'tree'。 您没有错误地使用 lxml,并不是说 lxml 在这种情况下不支持保留空格 (您可能认为有很多其他 SO 条目); 只是您无意中使用了一个 libxml2 版本,该版本的错误已被修复。

使用最近构建的 libxml2 驱动您的 lxml 安装,您发布的示例代码的输出将产生您所期望的结果(始终保留空白):

<pre>
<em>abc</em>

<em>def</em>

<sub>ghi</sub>

<sub>jkl</sub>

<em>mno</em>

<em>pqr</em>

</pre>