XPath的except运算符如何求差集?

except运算符用于求两个节点集的差集,返回第一个节点集中不在第二个节点集中的节点,语法为“节点集A except 节点集B”,适用于XPath 2.0及以上版本;在XPath 1.0中可通过[not()]谓词实现类似效果,如//p[not(@id=’p2′)];与union(并集)和intersect(交集)共同构成XPath集合操作体系,广泛应用于网页抓取中的内容清洗与干扰元素排除。

xpath的except运算符如何求差集?

XPath中的

except

运算符,简单来说,就是用来找出两个节点集之间独有的部分,也就是我们常说的“差集”。它会返回第一个节点集中存在,但第二个节点集中不存在的所有节点。

当我第一次接触到

except

这个操作符时,脑子里浮现的其实是数据库里SQL的

except

。它们的核心理念是相通的:从一个集合里剔除另一个集合的成员。在XPath里,这尤其有用,比如你想选定页面上所有链接,但又不包括那些指向外部网站的。或者,你可能想抓取所有段落,但要排除掉那些包含特定广告类的。

它的基本语法是:

节点集A except 节点集B

。这会返回一个全新的节点集,其中包含了所有属于

节点集A

,但却不属于

节点集B

的节点。

举个例子,假设我们有这样的HTML结构:

这是一个段落。

这是一个span。

这是另一个段落。

内部链接 外部链接

如果我们想选择所有

p

元素,但排除掉

id

p2

的那个,可以这样写:

//p except //p[@id='p2']

这个表达式会返回

这是一个段落。

再来一个更复杂的场景,比如我们想获取所有的

div

子元素,但又不想包含那些有

class="header"

div

。假设HTML是:

  
Header 1
Content 1
Header 2
Content 2

XPath可以写成:

//div[@class='main']/* except //div[@class='header']

这里,

//div[@class='main']/*

会选出所有

main

div

下的直接子元素(包括header和普通div)。

except //div[@class='header']

则把所有

header

类的

div

从结果中剔除。最终得到的就是

Content 1

Content 2

有一点需要注意,

except

操作符是XPath 2.0及以上版本才支持的。如果你在使用XPath 1.0的环境,比如一些老旧的XML解析库,或者某些浏览器内置的XPath引擎,你可能就无法直接使用它了。这时候,我们通常需要借助其他方法,比如结合

[not()]

谓词或者在编程语言层面进行过滤。这多少有点麻烦,但也不是没有办法。

XPath 1.0环境下如何实现差集操作?

这确实是个现实问题。我之前就遇到过,在一些遗留系统里,虽然XPath 2.0已经普及很久了,但它们的底层解析器依然停留在1.0版本。这时候

except

就用不上了,你得换个思路。

最常见的替代方案是利用谓词(predicates)中的

not()

函数。它的逻辑是“选择所有满足条件A的节点,并且这些节点不满足条件B”。语法通常是:

节点集A[not(条件B)]

举个例子,还是刚才那个需求:选择所有

p

元素,但排除掉

id

p2

的。在XPath 1.0中,你可以这样写:

//p[not(@id='p2')]

这会非常精准地选出所有

p

元素中,那些

id

属性不等于

p2

的。结果和

//p except //p[@id='p2']

是完全一样的。

再看那个剔除

header

div

的例子:HTML:

  
Header 1
Content 1
Header 2
Content 2

XPath 1.0的写法可以是:

//div[@class='main']/*[not(@class='header')]

这个表达式会先选择

class

main

div

下的所有直接子元素,然后通过

[not(@class='header')]

过滤掉那些

class

header

的。逻辑清晰,效果一致。

这种方式虽然不如

except

直观,因为它把“排除”的逻辑融入到了过滤条件里,但它在XPath 1.0时代是标准做法,而且效率通常也不错。理解了

not()

的用法,基本就能解决大部分差集需求了。当然,如果逻辑变得非常复杂,比如要从A中排除B和C,那

not()

的嵌套或者组合可能会变得有点冗长,这时候

except

的简洁性就体现出来了。

except

union

intersect

等集合操作符的区别与联系

当我们谈论

except

的时候,很难不联想到XPath里的其他集合操作符,比如

union

(联合)和

intersect

(交集)。它们都是处理节点集的利器,但各自的侧重点和应用场景大相径庭。

union

,顾名思义,就是把两个节点集的内容合并起来。它的语法是

节点集A | 节点集B

。这个操作符会返回所有在

节点集A

中或者在

节点集B

中的节点,并且会自动去重。比如说,你想选出页面上所有的

h1

h2

标题,你就可以写

//h1 | //h2

。它就像是SQL里的

union

或者数学里的并集。

intersect

(交集)则刚好相反,它会找出两个节点集共同拥有的节点。语法是

节点集A intersect 节点集B

。比如,你想找到所有同时具有

class="active"

class="selected"

div

元素,你可能会先选出所有

class="active"

div

,再选出所有

class="selected"

div

,然后用

intersect

找出它们的交集。在实际应用中,

intersect

用的频率可能不如

except

union

高,但它在需要精确匹配多个条件的场景下非常有用。

except

,我们已经详细讨论过了,它求的是差集,即从第一个集合中移除第二个集合共有的部分。

这三个操作符,

union

intersect

except

,共同构成了XPath 2.0强大的集合运算能力。它们让我们可以像操作数学集合一样来处理XML/HTML文档中的节点,极大地提高了XPath表达式的表达力和灵活性。我个人觉得,理解并熟练运用这些集合操作符,是掌握高级XPath技巧的关键一步。它们让原本需要多步筛选或者复杂逻辑才能实现的需求,变得一行代码就能搞定,效率提升是显而易见的。有时候,我甚至会把它们想象成数据处理管道中的不同阀门,各自完成特定的过滤或合并任务。

except

操作符在实际网页抓取中的应用案例

理论知识学得再好,最终还是要落到实际应用上。

except

操作符在网页抓取(Web Scraping)领域简直是神器般的存在,它能帮我们高效地剔除那些不想要的、干扰数据。

一个非常典型的场景是内容清洗。想象一下,你正在抓取一个新闻网站的文章内容。通常,文章主体会被放在一个特定的

div

或者

article

标签里。但在这个主体内容里,可能混杂着各种广告、推荐阅读、版权声明或者社交分享按钮,这些都不是你真正关心的文章文本。

假设文章内容在

里,而其中有一些广告块是

,或者图片说明是

。如果你直接抓取

//div[@id='article-body']//text()

,你可能会把广告文案和图片说明也抓进来。这时候,

except

就能派上用场了:

//div[@id='article-body']//*[not(self::script or self::style)] except //div[@class='ad-block'] except //figcaption

这个表达式的思路是:

先选出

article-body

下所有非脚本非样式的元素(

//*[not(self::script or self::style)]

,这是为了避免抓取JS代码或CSS样式)。从中剔除所有

ad-block

类的

div

。再剔除所有

figcaption

元素。这样,剩下的就是相对纯净的文章内容了。当然,你可能还需要进一步处理文本,比如去除多余的空格和换行符。

另一个例子是导航菜单的排除。你可能想抓取页面上所有的链接,但是导航菜单里的链接往往是重复的或者功能性的,你只想要正文或者侧边栏里的链接。假设导航菜单在

标签里:

//a except //nav//a

这会选中页面上所有

标签,然后排除掉所有在

标签内部的

标签。是不是很简洁?

有时候,网站会有一些通用的模板元素,比如页脚(footer)或者侧边栏(sidebar),它们包含一些你不想重复抓取的信息。如果这些元素有明确的标识(ID或Class),你就可以用

except

把它们从你的目标节点集中剔除。例如,抓取所有

div

但排除页脚和侧边栏:

//div except //footer//div except //aside//div

这些应用场景都体现了

except

的强大之处:它提供了一种声明式的方式来定义“不想要什么”,而不是“只想要什么”,这在面对复杂或不规则的HTML结构时,往往能带来意想不到的便利和效率。它让我能更专注于核心数据的提取,而不是纠结于如何绕过那些干扰元素。

以上就是XPath的except运算符如何求差集?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1430299.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月17日 03:30:36
下一篇 2025年12月13日 17:17:37

相关推荐

  • XPath的@通配符如何匹配所有属性?

    XPath的@通配符用于选取属性节点,结合*可匹配具有任意属性的元素,如//*[@*]选取含至少一个属性的元素,通过编程语言遍历属性名值,使用starts-with、namespace-uri等函数实现条件筛选与命名空间处理。 XPath的 @ 通配符本身并不直接匹配所有属性。它主要用于选取属性节点…

    2025年12月17日
    000
  • XPath的mod运算符怎么计算余数?

    xpath的mod运算符结果的符号始终与被除数相同,这与java等语言一致,但不同于python中结果符号与除数一致的取模方式;其计算逻辑为a mod b = a – (floor(a / b) * b),例如-5 mod 2结果为-1,而5 mod -2结果为1;该特性在节点筛选中极为…

    2025年12月17日
    000
  • XPath的normalize-space()函数有什么用?

    normalize-space()函数在XPath中用于清理字符串中的空白字符,它会移除字符串首尾的所有空白,并将内部连续的空白字符替换为单个空格,从而提升文本数据的规范性和可处理性。在网页抓取中,该函数广泛应用于文本精确匹配、数据清洗标准化、处理动态或用户输入内容以及合并多文本节点等场景,能有效解…

    2025年12月17日
    000
  • XPath的local-name()函数有什么用?

    local-name()函数用于提取XML节点名称的本地部分,忽略命名空间前缀。1. 使用local-name()=’title’可选择所有本地名为title的节点,如//[local-name()=’title’]能匹配book:title和arti…

    2025年12月17日
    000
  • XPath的attribute轴怎么选择属性节点?

    xpath中的attribute轴和@符号是一回事,@是attribute::的简写形式,两者功能完全相同;在实际使用中,通过//元素/@属性名可直接选取属性节点,如//div/@id;当需要根据属性值筛选时,可结合谓语使用,如//div[@id=’header’];而在处理…

    2025年12月17日
    000
  • XPath的translate()函数怎么替换字符?

    translate()函数用于字符替换,如将电话号码中的-和空格替换为点,其语法为translate(string, from, to),from中多余字符会被删除,且该函数可实现大小写转换但仅限ASCII,需注意from与to长度匹配及解析器差异。 XPath的 translate() 函数就像一…

    2025年12月17日
    000
  • XPath的通配符怎么匹配所有元素?

    答案:XPath中通配符可匹配所有元素节点,如//选择文档中全部元素,//div/选择div下所有子元素,结合属性如//[@class=’highlight’]可定位特定属性的任意元素,常用于动态结构或探索性选择,但可能引发性能问题和匹配过宽,需谨慎使用。 在XPath里,要…

    2025年12月17日
    000
  • XPath的|运算符如何合并多个结果集?

    xpath中的|运算符是节点集联合操作符,用于将多个xpath表达式匹配的节点集合并为一个无重复的集合,例如//h1 | //h2可同时选取所有h1和h2元素,它操作的是结果集的并集,而不同于and/or这类在谓词中对单个节点进行条件判断的布尔操作符,因此|适用于跨结构收集分散但逻辑相关的数据,在处…

    2025年12月17日
    000
  • 如何在Fortran中使用XML库处理科学数据XML?

    最直接且目前最可行的Fortran处理XML数据的方法是借助C语言XML解析库并通过Fortran 2003的ISO_C_BINDING模块实现互操作,具体做法是选用成熟的C库如libxml2,编写C语言封装函数作为接口,再在Fortran中声明对应的C绑定接口,实现XML文件的解析与数据提取,同时…

    2025年12月17日
    000
  • XPath的union运算符和|有什么区别?

    xpath中的union运算符和|符号功能等价,均用于合并节点集且结果按文档顺序排列、无重复节点,核心区别在于版本支持与语法风格:|是xpath 1.0及以上版本都支持的传统联合操作符,而union是xpath 2.0及以上版本引入的更易读的关键词形式;在实际使用中,若需兼容xpath 1.0环境(…

    2025年12月17日
    000
  • XPath的contains()方法怎么用?有哪些应用场景?

    “淘宝第一个程序员”蔡景现(花名多隆)已从阿里巴巴离职,结束25年任职生涯。作为淘宝初创核心工程师,他构建了淘宝交易系统,以技术实力闻名,曾以26亿身家登上胡润富豪榜,其阿里内外状态已显示为“退隐江湖”。 XPath的 contains() 方法,简单来说,就是用来判断一个字符串是否包含另一个特定的…

    2025年12月17日
    000
  • XPath的following-sibling轴如何选择同级?

    following-sibling轴用于选择当前节点之后同父级的所有同级节点,其定位精准且仅限于兄弟节点范围内,不会涉及父级、子级或其他无关部分;与following轴不同,following-sibling仅在同级节点中向后查找,而following轴则全局查找文档中所有后续节点,范围更广;通过结…

    2025年12月17日
    000
  • XPath的descendant轴如何选择所有后代?

    descendant轴用于选择指定节点的所有后代节点,语法为//node/descendant::*;2. 可通过具体节点名或谓词过滤精确选择;3. 与//区别在于descendant需指定起始节点且不包含自身;4. 使用时应注意性能,建议缩小范围并避免滥用通配符。 XPath的 descendan…

    2025年12月17日
    000
  • XPath的substring-after()函数如何截取?

    substring-after()用于截取分隔符后的字符串,如substring-after(“apple-banana-cherry”, “-“)返回”banana-cherry”;与substring-before()区别在…

    2025年12月17日
    000
  • XML的XPath轴(axis)有哪些?如何使用它们导航?

    选择合适的xpath轴能显著提升查询性能和准确性,应优先使用child::和attribute::等高效轴,避免滥用//,结合谓语过滤,注意命名空间和上下文节点,防止陷入性能差、匹配不精确等常见陷阱,最终实现高效精准的xml导航。 XPath轴是XML文档中用于从一个“上下文节点”出发,根据其与目标…

    2025年12月17日
    000
  • XPath的child轴和//有什么区别?

    child轴(或/)只搜索直接子节点,而//会递归搜索所有后代节点;例如在div下,/p仅选中直接子元素的p,而//p会选中所有层级的p,包括嵌套在span内的p;1. 当结构明确、需精确控制层级或追求性能时,应使用child轴(/);2. 当结构不确定、需全局搜索或从当前节点深层查找时,//更合适…

    2025年12月17日
    000
  • XPath的轴(axis)是什么?如何选择父节点?

    选择父节点使用parent轴或其缩写..,例如当前节点为 时,..或parent::book可选中其父节点;在复杂表达式中可结合属性选取如//book/title/parent::book/@isbn;..更简洁常用;其他常用轴包括child、ancestor、descendant、followin…

    2025年12月17日
    000
  • XPath的node()函数怎么匹配任何节点?

    node()函数在xpath中用于匹配任何类型的节点,包括元素、文本、属性、注释、处理指令和根节点,适用于需要获取父节点下所有子节点的场景。当处理混合内容、未知结构或进行文档调试时,node()能完整捕获所有节点类型,而不仅限于元素或文本。与更具体的节点测试如*(仅元素)或text()(仅文本)相比…

    2025年12月17日
    000
  • XPath的position()函数如何获取节点位置?

    使用position()函数可通过谓语结合位置条件选取节点,如/book/chapter[position() python的lxml库可直接用xpath()方法执行含position()的表达式,正确理解上下文和充分测试是确保选取准确的关键。 XPath的 position() 函数用于获取当前节…

    2025年12月17日
    000
  • XPath的intersect运算符怎么求交集?

    在xpath 1.0中可通过谓词表达式[count(. | $nodeset2) = count($nodeset2)]模拟节点集交集,例如//book[@category=’fiction’][count(. | //book[price > 30]) = count…

    2025年12月17日
    000

发表回复

登录后才能评论
关注微信