0

0

XPath的not()函数怎么否定表达式?

幻夢星雲

幻夢星雲

发布时间:2025-08-16 16:55:01

|

628人浏览过

|

来源于php中文网

原创

not()函数用于反转XPath表达式的布尔结果,常用于筛选不满足特定条件的节点。其基本形式为not(expression),可否定属性存在、属性值、文本内容或子元素存在性。常见用法包括//div[not(@class)]选择无class属性的div,//a[not(@target='_blank')]排除target为_blank的链接。误区包括混淆not()作用范围,如not(//div[@class='active'])返回布尔值而非节点集,正确写法应为//div[not(@class='active')]。not()可与and、or结合使用,遵循德摩根定律,如//div[not(@id) and not(@class)]等价于//div[not(@id or @class)]。性能上,not()本身开销小,但内部复杂表达式可能影响效率,建议避免全局搜索,优先在谓词内使用以提高效率。

xpath的not()函数怎么否定表达式?

XPath的

not()
函数,说白了,就是用来否定一个表达式的结果。它会把一个原本为真的条件变成假,把假的变成真。你把它想象成一个“非”门,输入是真,输出就是假;输入是假,输出就是真。这在我们需要选择那些“不符合”某个条件的元素时,简直是神器。

解决方案

要否定一个XPath表达式,你只需要将该表达式作为

not()
函数的参数。它的基本形式是
not(expression)
。这个
expression
可以是任何能产生布尔值(真或假)的XPath表达式。

举几个例子,你就能立刻明白它的威力了:

not()
函数非常灵活,它可以嵌套在更复杂的表达式中,或者与其他逻辑运算符(如
and
or
)结合使用,来实现更精细的筛选。

XPath中not()函数的基本用法与常见误区是什么?

说实话,

not()
函数用起来简单,但要真正理解它的“哲学”,避免踩坑,还是得掰扯掰扯。

基本用法:

正如前面提到的,

not()
的核心就是“反转”逻辑。它最常见的应用场景就是作为谓词(
[]
)的一部分,用来过滤节点集。

常见误区:

这里有些坑,我个人就掉过好几次,后来才慢慢琢磨明白:

  1. 误区一:对空节点集的理解。 当一个XPath表达式的结果是空节点集时,在布尔上下文中它会被转换为

    false
    。非空节点集则转换为
    true

    • 比如
      //div[not(./span)]
      :如果当前
      div
      下有
      span
      ./span
      就是非空节点集,转换为
      true
      not(true)
      就是
      false
      ,这个
      div
      不被选中。如果当前
      div
      下没有
      span
      ./span
      就是空节点集,转换为
      false
      not(false)
      就是
      true
      ,这个
      div
      被选中。这符合预期。
    • 但如果你写
      not(//div[@class='active'])
      ,这通常不是你想要的效果。这个表达式会检查整个文档中是否存在任何一个
      class
      active
      div
      。如果存在,整个表达式就是
      false
      。如果一个都没有,整个表达式就是
      true
      。它返回的是一个单一的布尔值,而不是一个节点集。你大概率是想选择那些
      class
      不是
      active
      div
      ,那应该是
      //div[not(@class='active')]
  2. 误区二:

    not()
    的位置和
    作用域
    not()
    放在谓词内部,是针对当前节点进行判断;放在整个表达式外面,是针对整个表达式的结果进行判断。

    • //div[not(@class='active')]
      :选择所有
      class
      属性不等于
      active
      div
    • not(//div[@class='active'])
      :判断文档中是否存在
      class
      active
      div
      ,并返回其相反的布尔值。这是个全局性的判断。
  3. 误区三:与

    and
    /
    or
    的结合(德摩根定律)。
    有时候我们想否定一个复合条件,比如“既不是A也不是B”。

    • not(conditionA and conditionB)
      等价于
      not(conditionA) or not(conditionB)
    • not(conditionA or conditionB)
      等价于
      not(conditionA) and not(conditionB)
      。 理解这一点能帮助你写出更清晰、更符合逻辑的XPath。例如,你想找既没有
      id
      属性也没有
      class
      属性的
      div
      //div[not(@id) and not(@class)]
      或者等价的
      //div[not(@id or @class)]
      。我个人更倾向于前者,感觉逻辑更直观一些。

如何利用not()函数选择不包含特定属性或子元素的节点?

这几乎是

not()
函数最经典的用途了,也是日常工作中非常高频的场景。

GPT Detector
GPT Detector

在线检查文本是否由GPT-3或ChatGPT生成

下载

选择不包含特定属性的节点:

  • 没有某个特定属性的节点: 如果你想找到页面上所有没有

    id
    属性的
    div
    元素,可以这样写:
    //div[not(@id)]
    这里的
    @id
    如果存在,就会被视为真,
    not()
    一否定就变假,该
    div
    不被选中。如果
    @id
    不存在,就是假,
    not()
    一否定就变真,该
    div
    就被选中。这非常简洁高效。

  • 某个属性的值不符合预期: 假设你有一堆链接,但你只想选择那些

    href
    属性不以
    #
    开头的(排除锚点链接):
    //a[not(starts-with(@href, '#'))]
    或者你想找所有
    img
    标签,但排除掉那些
    alt
    属性为空字符串的(通常意味着图片描述缺失):
    //img[not(@alt='')]

选择不包含特定子元素的节点:

  • 没有某个直接子元素的节点: 你可能想找到所有没有

    子元素的
    //div[not(./span)]
    这里的
    ./span
    表示查找当前
    div
    的直接子元素
    span
    。如果找到了,
    not()
    就让当前
    div
    不被选中;如果没找到,就选中它。

  • 没有某个特定类型的后代元素的节点: 如果你想找到所有

      列表,但排除掉那些内部任何地方(不一定是直接子元素)包含
      class
      selected
      • //ul[not(.//li[@class='selected'])]
        这里的
        .//li
        表示查找当前
        ul
        下的任意层级的
        li
        元素。

      • 不包含特定文本内容的节点: 比如你有一堆

        div
        ,你想找到那些内部文本不包含“广告”字样的
        div
        //div[not(contains(text(), '广告'))]
        或者更精确一点,不包含“免费”或“优惠”:
        //div[not(contains(text(), '免费') or contains(text(), '优惠'))]

      这些都是非常实用的场景,

      not()
      函数在这里发挥了它筛选“反向条件”的巨大作用。

      not()函数在复杂XPath表达式中的应用场景与性能考量

      在更复杂的XPath表达式里,

      not()
      函数就像一块乐高积木,可以灵活地嵌入,实现非常精细的筛选逻辑。但同时,我们也得稍微琢磨下它的性能,虽然在绝大多数Web抓取场景下,这点性能差异可能微不足道。

      复杂应用场景:

      1. 组合否定条件: 我们经常需要同时满足多个否定条件。比如,我想找一个

        div
        ,它既没有
        id
        属性,
        class
        也不是
        hidden
        //div[not(@id) and not(@class='hidden')]
        或者,你也可以利用德摩根定律,写成:
        //div[not(@id or @class='hidden')]
        这两种写法在逻辑上是等价的,具体用哪个,看你个人觉得哪个更清晰。我个人偏好第一个,感觉更直观。

      2. 否定函数结果:

        not()
        可以否定其他函数的返回结果。

        • 找那些文本内容不为空
          p
          标签:
          //p[not(normalize-space(text()) = '')]
          这里
          normalize-space()
          会移除文本前后的空白字符,并将内部连续空白替换为单个空格。
          not()
          再判断结果是否为空。
        • 找那些子元素数量不等于5的
          ul
          //ul[not(count(./li) = 5)]
          这等价于
          //ul[count(./li) != 5]
          ,但用
          not()
          有时候能让逻辑更统一。
      3. 结合位置谓词: 比如,选择一个

        ul
        中,除了第一个
        li
        之外的所有
        li
        //ul/li[not(position() = 1)]
        这等价于
        //ul/li[position() > 1]
        //ul/li[not(self::li[1])]

      性能考量:

      说实话,谈性能在XPath层面,很多时候有点“玄学”,因为实际的解析器实现、文档大小、以及你所使用的库或工具的优化程度都会有影响。但总的原则是,让你的表达式越具体越好,减少引擎的遍历范围。

      • not()
        本身通常不会成为性能瓶颈。
        它只是一个逻辑操作符。真正的性能开销通常来自于它内部的表达式,尤其是当这个表达式需要遍历大量节点或者执行复杂计算时。
      • 避免不必要的全局搜索: 如果你写
        not(//div[@class='active'])
        ,XPath引擎可能需要遍历整个文档来确定是否存在这样的
        div
        。如果你的目标是过滤一个已知的节点集,把
        not()
        放在谓词里通常更高效。 例如,你已经定位到了一组
        div
        ,现在想从这组
        div
        中筛选出没有特定属性的,那么
        //div[not(@attribute)]
        肯定比先获取所有
        div
        再在外部做
        not()
        判断要好。
      • 复杂表达式的优化:
        not()
        内部的表达式非常复杂时,性能可能会受影响。比如
        not(contains(concat(@id, @name, text()), 'keyword'))
        这种,因为它需要拼接字符串再进行搜索。 在某些极端情况下,如果性能真的成了问题,你可能需要考虑是否能用其他XPath函数或者在代码层面(比如Python的BeautifulSoup或lxml)进行后处理来达到同样的效果。但对于大多数Web抓取任务来说,不必过度担心
        not()
        的性能,它的简洁和表达力带来的效率提升往往远超那点微小的计算开销。

      最终,掌握

      not()
      的关键在于理解它如何将“真”变为“假”,以及它在不同上下文(特别是谓词中)的作用。多写多练,自然就熟了。

      相关专题

      更多
      python开发工具
      python开发工具

      php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

      769

      2023.06.15

      python打包成可执行文件
      python打包成可执行文件

      本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

      661

      2023.07.20

      python能做什么
      python能做什么

      python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

      764

      2023.07.25

      format在python中的用法
      format在python中的用法

      Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

      659

      2023.07.31

      python教程
      python教程

      Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

      1325

      2023.08.03

      python环境变量的配置
      python环境变量的配置

      Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

      549

      2023.08.04

      python eval
      python eval

      eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

      579

      2023.08.04

      scratch和python区别
      scratch和python区别

      scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

      730

      2023.08.11

      AO3中文版入口地址大全
      AO3中文版入口地址大全

      本专题整合了AO3中文版入口地址大全,阅读专题下面的的文章了解更多详细内容。

      1

      2026.01.21

      热门下载

      更多
      网站特效
      /
      网站源码
      /
      网站素材
      /
      前端模板

      精品课程

      更多
      相关推荐
      /
      热门推荐
      /
      最新课程
      最新Python教程 从入门到精通
      最新Python教程 从入门到精通

      共4课时 | 11.4万人学习

      Django 教程
      Django 教程

      共28课时 | 3.3万人学习

      SciPy 教程
      SciPy 教程

      共10课时 | 1.2万人学习

      关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
      php中文网:公益在线php培训,帮助PHP学习者快速成长!
      关注服务号 技术交流群
      PHP中文网订阅号
      每天精选资源文章推送

      Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号