为什么 lxml 在解析时关闭这个“ol”标签?

Why is lxml closing this "ol" tag when parsing?

提问人:dfrankow 提问时间:7/27/2021 更新时间:7/29/2021 访问量:119

问:

以下是一些 HTML:

<ol><ul><li>item</li></ul></ol>

和一些 Python 3 代码来解析它并重新打印它:lxml

import sys
from lxml import etree, html

document_root = html.fromstring(sys.stdin.read())
print(etree.tostring(document_root, encoding='unicode'))

输出如下:

<div><ol/><ul><li>item</li></ul>
</div>

在输出中,关闭 before 开始,这将更改列表结构。lxmlolul

它为什么要这样做?

我可以让 lxml 以保留列表结构的方式解析 HTML 吗?

编辑:请注意,如果我替换为 (),或者如果我替换为 (),则此示例可以很好地解析。输出与输入相同。ulol<ol><ol><li>item</li></ol></ol>olul<ul><ul><li>item</li></ul></ul>

我无法控制 HTML,它可能来自任何地方。

我正在使用从 PyPi 安装的 lxml 4.6.3 和 python 3.9。

或者,有没有另一种方法可以解析 HTML,我可以从中提取列表文本,同时保留 Python 中的列表结构?

正如您所知,我正在使用 lxml 来删除属性,所以下面是更接近我的用例的代码。但是,我想先给出最小的可重现测试用例。

更接近我的用例的代码:

import sys

import lxml.html.clean as clean
from lxml import etree, html

document_root = html.fromstring(sys.stdin.read())

cleaner = clean.Cleaner(safe_attrs_only=True, safe_attrs=frozenset())
cleansed = cleaner.clean_html(document_root)

# Do something with the lists in cleansed, defined by ol, ul, and li ..

print(etree.tostring(cleansed, encoding='unicode')
HTML 解析 lxml

评论

1赞 Jack Fleeting 7/27/2021
无法解释为什么,但似乎只有.它似乎适用于.htmldocument_root = etree.fromstring(sys.stdin.read())
1赞 dfrankow 7/27/2021
也许这是我尝试的事情。我认为 html 会更能适应来自世界的 html 片段,这些片段可能格式不那么好,但也许更大的威胁是 lxml 破坏了格式良好的 html。
0赞 Jack Fleeting 7/27/2021
“也许更大的威胁是 LXML 破坏了格式良好的 HTML”——是的,这也困扰着我;不记得曾经遇到过这种情况,这令人担忧。让我们希望 lxml 的 Powers that Be 之一能够注意到这一点并解决这个问题。
1赞 Martin Honnen 7/27/2021
我认为 HTML 4 和 HTML5 都不允许将元素作为元素的子元素,这可能是 HTML 解析器构建树结构的部分原因,该结构不代表您在输入标记中的嵌套。一个“传统的”HTML 4 解析器,就像可能在 lxml/libxml 的 HTML 解析器算法中实现的那样,是否对结构做了同样的更改,我不记得了,我不确定在哪里测试它。虽然两个 HTML5 验证器明确将您标记为当前浏览器不允许的子级,但似乎保留了这种嵌套。ulolulol
1赞 mzjn 7/27/2021
我也认为问题出在作为孩子。类似问题:stackoverflow.com/q/44976672/407651ulol

答:

1赞 Martin Honnen 7/29/2021 #1

我认为 HTML 4 和 HTML5 都不允许将元素作为元素的子元素。只有元素可以是直接子元素。ulolli

这可能就是为什么 HTML 解析器构建一个树结构,而不是表示输入标记中的嵌套。一个“传统的”HTML 4 解析器,就像可能在 lxml/libxml 的 HTML 解析器算法中实现的那样,是否对结构做了同样的更改,我不记得了,我不确定在哪里测试它。

虽然两个 HTML5 验证器将您标记为 的不允许的子级,但当前的浏览器似乎保留了这种嵌套。ulol