我正在尝试使用html5lib
treebuilder使用lxml
解析一些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.nsmap
dict不包含foo
命名空间,仅包含html
。
有没有人知道发生了什么以及如何解决这个问题?
稍后编辑:
这似乎是预期的行为:
如果使用的XML API限制元素和属性的本地名称中的允许字符,则该工具可以将所有元素和属性本地名称[...]映射到一组允许的名称,通过替换任何大写字母U不支持的字符和字符的Unicode代码的六位数[...] - Coercing an HTML DOM into an infoset
答案 0 :(得分:2)
一些观察结果:
HTML5似乎不支持xmlns属性。引用section 1.6 of the latest HTML5 specification:“...命名空间无法使用HTML语法表示,但它们在DOM和XHTML语法中受支持。”我看到你也尝试过使用XHTML,但是你现在正在使用HTML5,因此可能存在问题。 U+003A
是冒号的Unicode,所以xmlns
不知何故被注意到了,但是不知所措。
我不明白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>
或者,如果您希望使用纯html5lib
,则可以使用附带的simpletree
:
tree = html5lib.parse(resp_text, namespaceHTMLElements=True)
print tree.toxml()
虽然这不会破坏xmlns
属性,但遗憾的是simpletree
缺少ElementTree
功能更强大的xpath()
功能。