通过xpath实现if...else...逻辑

最近学习xpath(1.0)相关知识,在做数据抓取匹配的时候遇到一个问题,几经折腾解决了问题,记录下来分享给大家。

问题: 这是待匹配的数据,要抓取的数据在span标签class= ellipsis vip里面,【第一百一十二章 文章标题,该章节已被锁定】这两个文章标题,但是我们可以看到两个span标签里面的内容不一致,其中第二个span里面还有个span。

xml 复制代码
<dl class="Volume">
   <dt>
      <a class="folding" href="javascript:">- 收起</a>
      <span class="tit">正文</span><span class="info">已更新1111章</span>
   </dt>
   <dd>
         <a target="_blank"
            href="/chapter/1111/aaaa.html">
               <span class="ellipsis vip">
                     第一百一十二章 文章标题
               </span>
         </a>
         <a target="_blank"
            href="/chapter/2222/bbbb.html">
               <span class="ellipsis vip">
                     <span class="red">【锁】</span>
                     该章节已被锁定
               </span>
         </a>
   </dd>
</dl>

这就很麻烦了,我们写两个xpath去匹配这两种结构的数据

css 复制代码
//dl[@class="Volume"]//dd/a/span/text() //这个匹配第一个文章标题
//dl[@class="Volume"]//dd/a/span/span/following-sibling::text() //这个匹配第二个文章标题

而且代码还要加判断,选择哪种xpath匹配哪种数据,变得很繁琐。所以直接查找xpath语法是否有判断的逻辑,等于是说在xpath匹配的时候,就把判断加上了,直接写一个就行了。那究竟有没有呢?

解决问题: 通过谷歌搜索,在stackoverflow发现了这个回答: stackoverflow.com/questions/1... 里面的解决方法提出了一个这样的xpath表达式

bash 复制代码
concat(substring($stringA, 1 div $cond), substring($stringB, 1 div not($cond)))

这里有几个知识点要串联一下:

  • div 这是xpath的除法符号,1 div 1 ,就是1除以1的意思
  • not() 这个可以理解为取反,not(1)的结果就是0
  • substring 用来截取字符串,参数为substring(string,number,length),string用于指定要截取的字符串;number用于指定开始位置;length用于指定截取字符串的长度。如果缺少length参数将从开始位置number一直到截取字符串的长度。这个很重要,这个知识点要注意,比如substring("12345",1),取到的值就是12345,从第一位开始取值,substring("12345",2),取到的值就是2345,从第二位开始取值。但是如果number是个无穷大的值呢,我们的字符串都是有长度的,不可能无穷大,所以这时候就没有值可以返回了,这个是上面那个表达式实现的重点。
  • concat 用于串连多个字符串

好了,知识点讲完,我们回头来分析这个表达式,stringA,stringB我们可以理解为我们要返回的字符串,cond可以理解为我们的条件,如果cond为1,那前面的1 div 1就是1除以1等于1,后面的1 div not($cond)就变成1 div not(1),1 div 0就是1除以0,结果是个无穷大的值,这时候表达式就变成这样

bash 复制代码
concat(substring($stringA, 1), substring($stringB, 无穷大))
//substring($stringA, 1) 从第一位开始取值,等于直接返回了$stringA
//substring($stringB, 无穷大) 这个值就等于取值不了了,所以就是空,就变成了下面的表达式
concat($stringA) 
//其实就等于直接返回了$stringA这个字符串

那我们就尝试修改,看看是否能修改成上面的表达式,直接上成果

less 复制代码
//这里我把路径改短了,后面有完整代码
concat(substring(./span/span/following-sibling::text(), 1 div boolean(./span/span/following-sibling::text())),substring(./span/text(), 1 div not(./span/span/following-sibling::text())))

这个修改后整个表达式非常长,先解释逻辑,这里我们加上了个boolean,用来判断进行第一次匹配时是否满足./span/span/following-sibling::text(),也就是要匹配【该章节已被锁定】这个结果的,但是第一次其实是不满足的,所以第一个boolean(./span/span/following-sibling::text())就是返回0,第一个substring返回了空,第二个substring返回了匹配到的字符串。

接下来第二次匹配,./span/span/following-sibling::text()满足匹配,boolean(./span/span/following-sibling::text())返回1,第一个substring返回字符串。第二个substring的not(./span/span/following-sibling::text())取反返回了0,所以第二个substring没有返回字符串。

完整代码:

ini 复制代码
with open("test.html", encoding="utf-8") as f:
    data = f.read()

selector = etree.HTML(data)
lists = selector.xpath('//dl[@class="Volume"]//dd/a')

for bookList in lists:
    name = bookList.xpath('concat(substring(./span/span/following-sibling::text(), 1 div boolean(./span/span/following-sibling::text())),substring(./span/text(), 1 div not(./span/span/following-sibling::text())))').strip()
    print(name)
相关推荐
ccchen88813 小时前
Discuz X5.0 免登录采集发布插件 - 免费使用指南
经验分享·爬虫·火车头·disucz论坛采集发布·自动采集发布
小白学大数据14 小时前
Python 爬虫爬取应用商店数据:请求构造与数据解析
前端·爬虫·python·数据分析
深蓝电商API16 小时前
电商网站滑块验证码破解:OpenCV图像识别+轨迹模拟方案
爬虫·滑块验证码
Land032919 小时前
指纹浏览器自动化集成方案|多浏览器RPA适配实战记录
运维·人工智能·爬虫·python·selenium·自动化·rpa
深蓝电商API20 小时前
淘宝反爬升级应对:从Selenium到Playwright的迁移实践
爬虫·淘宝
WL_Aurora1 天前
Python爬虫实战(二):百度热搜榜单爬取
爬虫·python
Marvel__Dead1 天前
微调 Gemma 4 识别腾讯天御全系列验证码【解决方案-一个模型识别 滑块|文字点选|图标点选|空间点选】
人工智能·爬虫·python·验证码识别·ai 大模型
跨境数据猎手1 天前
反向海淘代购集运系统三种搭建路径对比:自研、开源二开、SaaS
爬虫·系统架构·开源
川冰ICE1 天前
Python爬虫实战⑲|Pandas数据合并与重塑,多数据源整合
爬虫·python·pandas
feasibility.2 天前
反爬十层妖塔:现代爬虫攻防的立体战争
爬虫·python·科技·scrapy·rust·go·硬件