2

我正在尝试html5lib使用lxmltreebuilder 解析一些 HTML 内容。注意:我正在使用requests库来获取内容,内容是 HTML5(尝试使用 XHTML - 结果相同)。

当我简单地输出 HTML 源代码时,它看起来还不错:

response = requests.get(url)
return response.text

返回

<html xmlns:foo="http://www.example.com/ns/foo">

但是当我实际使用 html5lib 解析它时,会发生一些奇怪的事情:

tree = html5lib.parse(response.text, treebuilder = 'lxml', namespaceHTMLElements = True)
html = tree.getroot()
return lxml.etree.tostring(html, pretty_print = False)

返回

<html:html xmlns:html="http://www.w3.org/1999/xhtml" xmlnsU0003Afoo="http://www.example.com/ns/foo">

注意这xmlnsU0003Afoo件事。

此外,html.nsmapdict 不包含foo命名空间,仅包含html.

有谁知道发生了什么以及我该如何解决这个问题?

后期编辑:

这似乎是预期的行为:

如果正在使用的 XML API 限制了元素和属性的本地名称中允许的字符,那么该工具可以将所有元素和属性的本地名称 [...] 映射到一组允许的名称,方法是替换任何不符合条件的字符。 '不支持大写字母 U 和字符的 Unicode 代码的六位数字 [...] -将 HTML DOM 强制转换为信息集

4

1 回答 1

2

几点观察:

  • HTML5 似乎不支持 xmlns 属性。引用最新 HTML5 规范的第 1.6 节:“......命名空间不能使用 HTML 语法表示,但它们在 DOM 和 XHTML 语法中受支持。” 我看到您也尝试过使用 XHTML,但您当前使用的是 HTML5,因此可能存在问题。U+003A是冒号的Unicode,所以不知何故xmlns被注意到但被弄乱了。

  • 至少 PHP 版本的自定义命名空间元素存在一个未解决的问题。

  • 我不明白html5lib这里的作用。为什么不直接使用lxml

from lxml import etree

tree = etree.fromstring(resp_text)
print etree.tostring(tree, pretty_print=True)

这似乎做你想做的事,没有html5lib和没有愚蠢的xmlnsU0003Afoo错误。使用我使用的测试 HTML,我得到了正确的输出(如下),并tree.nsmap包含一个'foo'.

<html xmlns:foo="http://www.example.com/ns/foo">
    <head>
        <title>yo</title>
    </head>
    <body>
        <p>test</p>
    </body>
</html>

或者,如果你想使用 pure html5lib,你可以使用包含的simpletree

tree = html5lib.parse(resp_text, namespaceHTMLElements=True)
print tree.toxml()

虽然这不会破坏xmlns属性,但simpletree不幸的是缺少更强大的ElementTree功能,例如xpath().

于 2012-09-03T21:38:58.570 回答