Python + lxml: 如何找到标签的命名空间?
我正在用 Python 和 lxml 处理一些 HTML 文件。其中一些文件是用 MS Word 编辑过的,里面有些 <p>
标签被写成了 <o:p> </o:p>
这样的形式。IE 和 Firefox 浏览器不把这些 MS 标签当成真正的 <p>
标签来处理,所以在 <o:p>
标签前后不会显示换行,而这就是原始编辑者格式化文件的方式,比如在 周围没有空格。
而 lxml 则比较整洁,处理完这些 HTML 文件后,我们发现所有的 <o:p>
标签都被改成了正确的 <p>
标签。不幸的是,经过这样的整理后,两个浏览器现在在所有的 周围都显示了换行,这样就破坏了原来的格式。
所以,我的想法是遍历所有的 <o:p>
标签,要么把它们删掉,要么把它们的 .text 属性加到父元素的 .text 属性上,也就是去掉 <o:p>
标签的标记。
from lxml import etree
import lxml.html
from StringIO import StringIO
s='<p>somepara</p> <o:p>msoffice_para</o:p>'
parser = lxml.html.HTMLParser()
html=lxml.html.parse( StringIO( s), parser)
for t in html.xpath( "//p"):
print "tag: " + t.tag + ", text: '" + t.text + "'"
结果是:
tag: p, text: 'somepara'
tag: p, text: 'msoffice_para'
所以,lxml 去掉了标签标记中的命名空间名称。有没有办法知道哪个 <p>
标签来自哪个命名空间,这样我就只删掉 <o:p>
的标签?
谢谢。
2 个回答
0
如果你的HTML代码格式正确的话,可以使用 etree.XMLParser
来处理。否则,可以试试unutbu的回答。
1
根据HTML的规范:“HTML语法不支持命名空间声明”。所以我觉得lxml.html.HTMLParser
会去掉或忽略命名空间。
不过,BeautifulSoup解析HTML的方式不同,所以我想试试看。如果你也安装了BeautifulSoup,可以像这样用lxml的BeautifulSoup解析器:
import lxml.html.soupparser as soupparser
import lxml.html
import io
s='<p>somepara</p> <o:p>msoffice_para</o:p>'
html=soupparser.parse(io.BytesIO(s))
BeautifulSoup不会去掉命名空间,但它也不会把命名空间当成命名空间来识别。相反,它只是标签名称的一部分。
换句话说,
html.xpath('//o:p',namespaces={'o':'foo'})
这样做是行不通的。但是这个变通方法/小技巧
for t in html.xpath('//*[name()="o:p"]'):
print "tag: " + t.tag + ", text: '" + t.text + "'"
可以得到
tag: o:p, text: 'msoffice_para'