通过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)
相关推荐
喵手21 小时前
Python爬虫实战:全站 Sitemap 自动发现 - 解析 sitemap.xml → 自动生成抓取队列的工业级实现!
爬虫·python·爬虫实战·零基础python爬虫教学·sitemap·解析sitemap.xml·自动生成抓取队列实现
iFeng的小屋21 小时前
【2026年新版】Python根据小红书关键词爬取所有笔记数据
笔记·爬虫·python
Love Song残响1 天前
揭秘Libvio爬虫:动态接口与逆向实战
爬虫
喵手1 天前
Python爬虫实战:构建招聘会数据采集系统 - requests+lxml 实战企业名单爬取与智能分析!
爬虫·python·爬虫实战·requests·lxml·零基础python爬虫教学·招聘会数据采集
iFeng的小屋1 天前
【2026最新当当网爬虫分享】用Python爬取千本日本相关图书,自动分析价格分布!
开发语言·爬虫·python
数研小生1 天前
关键词搜索京东列表API技术对接指南
大数据·数据库·爬虫
喵手1 天前
Python爬虫实战:网页截图归档完全指南 - 构建生产级页面存证与历史回溯系统!
爬虫·python·爬虫实战·零基础python爬虫教学·网页截图归档·历史回溯·生产级方案
Blurpath住宅代理1 天前
动态代理的五大优点:提升爬虫效率与安全性
网络·爬虫·动态ip·住宅ip·住宅代理
有代理ip1 天前
Python 与 Golang 爬虫的隐藏优势
爬虫·python·golang
深蓝电商API1 天前
常见反爬机制分类及对应破解思路
爬虫·python