在 Python 中使用 XPath

根据字节点中的属性值提取父节点

</br>

今天使用 Python 的 lxml 模块来提取网页中的内容, 有一个 XPath 的用法不明白, 问题是, table 子节点下有一系列 tr 子节点, 每个 tr 子节点里有 3 列 (td), 如果 td 中 style 属性的值为 color: 0, 那么就不提取它所属的这一 tr 子节点。

查了很久 stackoverflow 才解决, 方法一:

from lxml import etree

html = '''
<html>
<table>
<tr id="id_l107" class="new nick nick_cxreg">
    <td class="time" ><a href="/perl6/2016-09-21>05:07</a></td>
    <td style="color: #8d8100" class="nick">cxreg</td>
    <td class="msg">probably useful</a></td>
</tr>
    
<tr id="id_l108" class="new nick nick_mask">
    <td class="time" ><a href="/perl6/2016-09-21>05:09</a></td>
    <td style="color: #8d8100" class="nick">mask</td>
    <td class="msg">maybe better directed at <a href="/moarvm/today">#moarvm</a></td>
</tr>

<tr id="id_l74" class="cont special dark">
    <td class="time" ><a href="/perl6/2016-09-21>02:37</a></td>
    <td style="color: 0" class="nick"></td>
    <td class="msg">mcmillhj joined <a href="/perl6/today">#perl6</a></td>
</tr>
<table>
</html>
'''


selector = etree.HTML(html)
content = selector.xpath('//tr[descendant::td[@style!="color: 0"]]/td/text()')

for each in content:
    print(each)

打印出:

cxreg
probably useful: 
mask
maybe better directed at 

说明得到我们想要的结果了。怎么验证我们取得的是两个 tr 呢?

content = selector.xpath('//tr[descendant::td[@style!="color: 0"]]')

打印出

<Element tr at 0x139c3b0>
<Element tr at 0x139c368>

说明的确提取出了 2 个 tr 元素。descendant 是后代的意思。上面那句代码意思是

过滤 tr 元素, 如果 tr 的后代元素 td 的属性 style 值不为 "color: 0", 那么就提取这个 tr 子节点。否则不提取。

方法二,先过滤掉 td 然后使用 .. 语法返回到父级元素:

content = selector.xpath('//tr/td[starts-with(@style,"color: #")]/../td/text()')

这里找到 td 元素中属性以 color: #开头的 td (过滤掉了 color: 0 这样的 td), 然后使用 .. 语法得到只含有 color: # 子元素的 tr 父节点。以上两种方法异曲同工, 殊途同归。并且方法二最后得到的也是两个 tr 元素:

content = selector.xpath('//tr/td[starts-with(@style,"color: #")]/..')

打印:

<Element tr at 0x222f170>
<Element tr at 0x222f198>

程序最后主要代码如下:

content = selector.xpath('//tr[descendant::td[@style!="color: 0"]]')
for each in content:
    info = each.xpath('string(.)')
    msg = info.replace('\n', '')
    print(msg)
    print('-' * 85)
xpath.png

lxml 的安装

</br>
关于 lxml 的安装, Python 2.7 以下的就不说了, 说下 Python 3 下怎么安装 lxml:

Windows 7 32bit/64bit 系统下直接使用 pip install lxml 会提示 lxml Unable to find vcvarsall.bat。 我们采用本地安装, 线安装 wheel 模块:

pip install wheel

然后到模块仓库pythonlibs (相当于 Perl 的 metacpan)下载 lxml, 我下载的是 lxml-3.6.4-cp35-cp35m-win32.whl(即使你是 64 bit的系统)。然后在该文件所在目录下执行

pip install  lxml-3.6.4-cp35-cp35m-win32.whl

这样就安装成功了。如下图所示

result.png

Ubuntu 系统下你需要先安装依赖包:

sudo apt-get libxml2, libxml2-devel, libxlst, libxlst-devel, python-libxml2, python-libxslt

然后再安装

pip install lxml
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容