lxml html5parser似乎忽略了我传递给它的任何namespaceHTMLElements=False
选项。它将我提供的所有元素放入HTML命名空间而不是(预期的)void命名空间。
这是一个简单的案例,可以重现问题:
echo "<p>" | python -c "from sys import stdin; \
from lxml.html import html5parser as h5, tostring; \
print tostring(h5.parse(stdin, h5.HTMLParser(namespaceHTMLElements=False)))"
这个的输出是这样的:
<html:html xmlns:html="http://www.w3.org/1999/xhtml"><html:head></html:head><html:body><html:p>
</html:p></html:body></html:html>
可以看出,html
元素和HTML名称空间中的所有其他元素。
预期的输出是:
<html><head></head><body><p>
</p></body></html>
我认识到namespaceHTMLElements
是一个html5lib选项,而不是lxml直接执行任何操作的本机lxml选项。 lxml应该只调用html5lib并将该选项传递给html5lib,以便html5lib按预期使用它。
我仍然没有办法让lxml html5parser兑现namespaceHTMLElements
。但要明确的是,另一种方法是直接调用html5lib,如下所示:
echo "<p>" | python -c "from sys import stdin; \
import html5lib; from lxml import html; \
doc = html5lib.parse(stdin, treebuilder='lxml', namespaceHTMLElements=False); \
print html.tostring(doc)"
我已经知道的一些事情:
html
element must be placed into the HTML namespace - html5lib所做的namespaceHTMLElements=False
作为选项来覆盖默认的“将html
元素放入HTML命名空间”行为。namespaceHTMLElements=False
传递给它时,一切都按预期工作 - html
元素进入void命名空间。将一些printf攻击到html5lib源代码中,我观察到:
namespaceHTMLElements=False
调用html5lib namespaceHTMLElements
,然后是第二次namespaceHTMLElements=False
鉴于上述情况,很明显问题出在lxml和html5lib之间的界面中。我不确定为什么lxml会两次调用html5lib,但我认为这可能是因为出于某种原因它首先尝试创建自己的XHTMLParser
的新实例,然后再做我实际要求它做的事情,这只是为了创建自己的HTMLParser
。
因此,它可能会对html5lib进行两次调用,导致html5lib排序“锁定”第一次调用产生的默认namespaceHTMLElements=True
行为,然后忽略namespaceHTMLElements=False
指令它在第二次通话中看到它。
也许按照它的方式进行两次调用,lxml要么在html5lib中打破一些假设,要么实际上误用了html5lib API,而不是设计使用它。
或许原因根本不是lxml对html5lib进行两次单独调用的结果,而是使用html5lib接口的方式中的其他一些问题。
无论如何,我有兴趣听别人说是否有其他人遇到过这个问题而且有一个解决方法 - 或者至少对它为什么会发生这种情况有所了解。
答案 0 :(得分:0)
我已经在源代码中跟随了lxml如何将params移植到html5lib。大多数函数都有一个整理* kws,然后交给下一个函数。在调用实际的html5解析器的最后一步中,将其删除,并使用2个固定参数调用解析器。
(昨天我遇到了同样的问题,只是解决了这个问题,忘记了细节,允许我放弃任何代码片段和参考资料。)
无论如何,这证实了在2018年,直接调用html5lib仍然是首选方法,如果由于某种原因调用lxml自己的解析器不是一个选项。
(我的用例是:解析蹩脚的HTML并拥有xpath。)