根据字节点中的属性值提取父节点
</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)
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
这样就安装成功了。如下图所示
Ubuntu 系统下你需要先安装依赖包:
sudo apt-get libxml2, libxml2-devel, libxlst, libxlst-devel, python-libxml2, python-libxslt
然后再安装
pip install lxml