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>

&lt;div class="content"&gt;
 &lt;table width="800" cellspacing="0" cellpadding="0" align="center"&gt;
    &lt;tbody&gt;
     &lt;tr&gt;&lt;th colspan="5" class="pit" align="center"&gt;踏步机&lt;/th&gt;&lt;/tr&gt;
     &lt;td&gt;&lt;/td&gt;
    &lt;/tbody&gt;
 &lt;/table&gt;
&lt;/div&gt;

考虑到方便表达 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提取元素,目标混在多个节点名称相同之中,处理思路应该怎么做?

4 回复

//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

关键点:

  1. 用属性或文本定位锚点:找到能唯一区分这些相同节点的特征(比如特定的classidtext())。
  2. 使用轴(axis):比如following-sibling::parent::ancestor::,从锚点跳到目标节点。
  3. 在谓词中过滤:在[]里加条件,比如[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>

回到顶部