Python爬虫中通过XPath提取元素,目标混在多个节点名称相同之中,处理思路应该怎么做?
<div id="tranData">
<div class="tyfrom">
<div id="home"><img src="/img/223325.png" width="80" height="80"></div>
</div>
<div class=“fat4”>
<table width=“100%” cellspacing=“0” cellpadding=“0”>
<tbody>
<tr>
<th colspan=“5” class=“abc” align=“center”>
课程表
</th>
</tr>
</table>
</div>
<div class=“content”>
<table width=“800” cellspacing=“0” cellpadding=“0” align=“center”>
<tbody>
<tr><th colspan=“5” class=“pit” align=“center”>哑铃</th></tr>
<td></td>
</tbody>
</table>
</div>
<div class=“content”>
<table width=“800” cellspacing=“0” cellpadding=“0” align=“center”>
<tbody>
<tr><th colspan=“5” class=“pit” align=“center”>跑步机</th></tr>
<td>
<tr align=“center”>
<td class=“a1” width=“320”>
<a href=“http://192.168.1.155/sport/record/id1661.html” target="_blank" title=“38 分钟”>38 分钟</a>
</td>
<td class=“a7” width=“30”>
<img src="/img/sh_img/finish.png" title="" style=“cursor:pointer;”>
</td>
<td class=“a3” width=“100”>38Min.</td>
<td class=“a1” width=“30”>14:29</td>
<td class=“a3” width=“320”>15:07</td>
</tr>
</td>
</tbody>
</table>
</div>
<div class="content">
<table width="800" cellspacing="0" cellpadding="0" align="center">
<tbody>
<tr><th colspan="5" class="pit" align="center">踏步机</th></tr>
<td></td>
</tbody>
</table>
</div>
考虑到方便表达 html 代码的结构,瘦身了内容,调整了代码格式缩进,方便大家理解我的问题
1、通过 xpath,定位到了
//*[[@id](/user/id)="tranData"]
2、我想提取 tranData 节点,下面的跑步机内容,在这个代码中是 content[2],但页面会根据情况变化,有可能会是[6]/[7]/[8]这样。在'跑步机'所在的 content 节点里,唯一特征就是有跑步机三个字了(对,就是 text()),其它的 content 格式是一致的
3、etree.xpath,html.xpath 用什么方法能定位到这个 content,并把节点的代码弄出来呢?
4、如何按顺序提取跑步机 content 下面的 td 的 text()内容? (td 的 class 并不是每条记录都固定是 a*)
感谢大家热心解答!!
Python爬虫中通过XPath提取元素,目标混在多个节点名称相同之中,处理思路应该怎么做?
//div[…/th/text()=‘跑步机’]获取父节点
用父节点遍历子节点,不要用硬编码
这种情况挺常见的,XPath里节点名一样但内容混杂,直接按位置或标签名抓肯定乱套。核心思路是往上找能区分它们的父节点或祖先节点的特征,用这些特征来定位。
举个例子,假设你要爬一个商品列表页,<div class="item">里混着“已售罄”和“有货”的商品,它们的内部结构几乎一样。你不能直接//div[@class="item"]全抓,得用包含特定文本的兄弟节点或父节点的属性来过滤。
代码示例: 假设HTML结构如下(简化版):
<div class="product-list">
<div class="item">
<span class="status">有货</span>
<h3>商品A</h3>
</div>
<div class="item">
<span class="status">已售罄</span>
<h3>商品B</h3>
</div>
<div class="item">
<span class="status">有货</span>
<h3>商品C</h3>
</div>
</div>
你只想提取“有货”的商品标题。XPath可以这样写:
from lxml import etree
html = """(上面的HTML内容)"""
tree = etree.HTML(html)
# 思路:先定位到包含“有货”文本的span,再找其父节点div下的h3
titles = tree.xpath('//div[@class="item"][span[@class="status" and text()="有货"]]/h3/text()')
# 或者:先定位到“有货”的span,再找其后续兄弟节点h3(如果结构固定)
# titles = tree.xpath('//span[@class="status" and text()="有货"]/following-sibling::h3/text()')
for title in titles:
print(title)
输出:
商品A
商品C
关键点:
- 用属性或文本定位锚点:找到能唯一区分这些相同节点的特征(比如特定的
class、id、text())。 - 使用轴(axis):比如
following-sibling::、parent::、ancestor::,从锚点跳到目标节点。 - 在谓词中过滤:在
[]里加条件,比如[span[@class="status" and text()="有货"]],直接筛选出符合条件的父节点。
如果页面结构更复杂,可能需要组合多个条件,或者用contains()函数匹配部分属性。总之,XPath足够灵活,关键是想清楚节点的层次关系和区分特征。
总结:找上层或兄弟节点的特征来定位。
<tr><th colspan=“5” class=“pit” align=“center”>跑步机</th></tr>
<td>
这里第二行的 <td> 应该是多余的<br>In [215]: from scrapy import Selector<br><br>In [216]: sel = Selector(text=doc)<br><br>In [217]: sel.xpath("//th[contains(text(), '跑步机')]/parent::tr/following-sibling::tr/td/text()").extract()<br>Out[217]:<br>['\n ',<br> '\n ',<br> '\n ',<br> '\n ',<br> '38Min.',<br> '14:29',<br> '15:07']<br><br>In [218]: sel.xpath("//th[text()='跑步机']/parent::tr/following-sibling::tr/td/text()").extract()<br>Out[218]:<br>['\n ',<br> '\n ',<br> '\n ',<br> '\n ',<br> '38Min.',<br> '14:29',<br> '15:07']<br><br>In [219]:<br>
参考 #1 的写法:<br>In [229]: sel.xpath("//tbody[tr/th/text()='跑步机']/tr[@align='center']/td/text()").extract()<br>Out[229]:<br>['\n ',<br> '\n ',<br> '\n ',<br> '\n ',<br> '38Min.',<br> '14:29',<br> '15:07']<br><br>In [230]:<br>

