通过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)
相关推荐
API快乐传递者5 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python
兜里有糖请分享15 小时前
Python中序列化/反序列化JSON格式的数据
爬虫·python
亿牛云爬虫专家21 小时前
用Puppeteer点击与数据爬取:实现动态网页交互
javascript·爬虫·爬虫代理·puppeteer·数据·代理ip·16yun
API快乐传递者1 天前
利用Python 的爬虫技术淘宝天猫销量和库存
开发语言·爬虫·python
操练起来1 天前
【Python实战案例】爬虫项目实例(附赠源码)
数据库·爬虫·python
编码小袁1 天前
利用爬虫爬取网站信息
爬虫
孤寒者1 天前
【实战篇】requests库 - 有道云翻译爬虫 【附:代理IP的使用】
爬虫·代理ip·隧道代理·有道云翻译爬虫·青果代理ip
=(^.^)=哈哈哈1 天前
从安全角度看多线程(附Golang举例)
爬虫·python·golang
Python_trys1 天前
Python网络爬虫入门篇!
开发语言·爬虫·python
摇光~1 天前
7篇Python爬虫实例,直接代码可运行,全网最全,注释超详细(适合收藏)——2、爬取图片信息。
开发语言·爬虫·python