文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

肝了三天三夜,一文道尽 Python的 Xpath 解析!

2024-12-02 17:24

关注

大家在写爬虫时,往往获取到网页之后,需要从网页中提取我们需要的信息。这时候就需要用到 xpath 或者 css 选择器来定位页面元素信息。但是,由于这两者都是非人性化的语法,导致好多人望而生畏,经常为这个发愁。

今天我就尝试用一篇文章来道尽 xpath 解析 HTML 的方方面面,希望大家看完这篇文章后,从此不再害怕 xpath 解析。

路径表达式

我们先放上一段 HTML 代码:

  1.  
  2.    
  3.      </span></li><li><span>      Xpath test page </span></li><li class="alt"><span>     
  4.    
  5.    
  6.     "navli"
  7.       "nav_tit"
  8.         "https://www.baidu.com/"
  9.           百度 
  10.          
  11.         "group" /> 
  12.        
  13.     
 
  •     "navli"
  •       "nav_tit"
  •         "https://news.cctv.com/"
  •           新闻频道 
  •          
  •        
  •     
  •  
  •     "navli"
  •       "nav_tit"
  •         "https://sports.cctv.com/"
  •           体育频道 
  •          
  •        
  •      
  •    
  •  
  • 接下来,我们针对这段 HTML 代码来进行 xpath 解析。

    要进行 xpath 解析,我们先要将 HTML 文本转化成对象:

    1. from lxml import etree 
    2.  
    3. text = ''
    4.  
    5.             'ultest'
    6.                  "item-0">"link1.html">first item
    7.  
    8.                  "item-1">"link2.html">second item
    9.  
    10.                  "item-inactive">"link3.html">third item
    11.  
    12.                  "item-1">"link4.html">fourth item
    13.  
    14.                  "item-0">"link5.html">fifth item # 注意,此处缺少一个 
    15.  闭合标签 
    16.               
    17.           
    18. ''
    19. # 调用HTML类进行初始化,这样就成功构造了一个XPath解析对象。 
    20. page = etree.HTML(text)     
    21. print(type(page)) 

    我们可以看到打印的结果:

    1. 'lxml.etree._Element'

    nodename

    nodename 表示根据标签名字选取标签,注意只会选择子标签!比如:如果是儿子的儿子则选取不到。

    1. print(page.xpath("body")) 
    2.  
    3. //[at 0x1966d1c48c0>] 
    4.  
    5. print(page.xpath("ul")) 
    6.  
    7. // [] 

    这个 nodename 我有点不是太清楚,当我使用 body 时,可以找到出 body 节点元素,但是使用 ul 时,找不到 ul 节点元素,打印的是空。这个网上搜索也没有什么准确的答案,如果你知道这里面的原理,还请告诉我。

    /

    / 表示从根节点选取一级一级筛选(不能跳)。

    1. print(page.xpath("/html")) 
    2.  
    3. // [at 0x27107f41100>] 
    4.  
    5. print(page.xpath("/body")) 
    6.  
    7. // [] 

    可以看到,我选取根节点 html ,可以打印出根节点元素,而我选取 body 打印时,是找不到的,这个符号只能从根节点开始找。

    //

    // 表示从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。注意:是所有符合条件的。

    1. print(page.xpath("//li")) 
    2.  
    3. // [at 0x1cd2a325780>, at 0x1cd2a325840>, at 0x1cd2a3259c0>, at 0x1cd2a325b00>, at 0x1cd2a325ac0>] 

    .

    . 表示选取当前标签。

    1. ul = page.xpath("//ul"
    2. print(ul) 
    3. print(ul[0].xpath(".")) 
    4. print(ul[0].xpath("./li")) 
    5.  
    6. // [at 0x1cd2a325840>] 
    7. // [at 0x1cd2a325840>] 
    8. // [at 0x1cd2a325700>, at 0x1cd2a325b00>, at 0x1cd2a325640>, at 0x1cd2a325ac0>, at 0x1cd2a325c00>] 

    我们先定位到 ul 元素节点,这里的结果是一个列表,然后再打印当前节点列表的第一个 ul,接着我们打印这个 ul 节点的子节点 li。

    ..

    .. 表示选取当前标签的父节点。

    1. print(ul[0].xpath("..")) 
    2.  
    3. // [] 

    这里打印第一个 ul 节点的父元素,也就是 div 。

    @

    @ 表示获取标签的属性值。

    1. print(ul[0].xpath("@id")) 
    2.  
    3. // ['ultest'

    我们打印第一个 ul 节点的 id 属性,可以看到结果是 ‘ultest’。

    谓语

    谓语用来查找某个或某些特定的节点或者包含某个指定值的节点。谓语被嵌在方括号中。

    1. //a[n] n为大于零的整数,代表子元素排在第n个位置的元素 
    2. //a[last()]   last()  代表子元素排在最后个位置的元素 
    3. //a[last()-]  和上面同理,代表倒数第二个 
    4. //a[position()<3] 位置序号小于3,也就是前两个,这里我们可以看出xpath中的序列是从1开始 
    5. //a[@href]    拥有href的元素 
    6. //a[@href='www.baidu.com']    href属性值为'www.baidu.com'元素 
    7. //book[@price>2]  price值大于2的元素 

    同样的,我们来举一些例子:

    1. # 第三个li标签 
    2. print(page.xpath('//ul/li[3]')) 
    3. # 最后一个li标签 
    4. print(page.xpath('//ul/li[last()]')) 
    5. # 倒数第二个li标签 
    6. print(page.xpath('//ul/li[last()-1]')) 
    7. # 序号小于3的li标签 
    8. print(page.xpath('//ul/li[position()<3]')) 
    9. # 有class属性的li标签 
    10. print(page.xpath('//li[@class]')) 
    11. # class属性为item-inactive的li标签 
    12. print(page.xpath("//li[@class='item-inactive']")) 

    获取文本

    text()

    我们用text()获取某个节点下的文本:

    1. print(page.xpath('//ul/li/a/text()')) 
    2.  
    3. // ['first item''second item''third item''fourth item''fifth item'

    string()

    我们用string()获取某个节点下所有的文本:

    1. print(page.xpath('string(//ul)')) 

    输出内容为:

    1. first item 
    2. second item 
    3. third item 
    4. fourth item 
    5. fifth item # 注意,此处缺少一个  闭合标签 

    fifth item # 注意,此处缺少一个 闭合标签

    通配符

    * 表示匹配任何元素节点:

    1. print(page.xpath('//li/*')) 
    2.  
    3. // [at 0x208931f0f00>, at 0x208931f0f40>, at 0x208931f0c40>, at 0x208931f0d80>, at 0x208931ff080>] 

    @* 表示匹配任何属性节点:

    1. print(page.xpath('//li/@*')) 
    2.  
    3. // ['item-0''item-1''item-inactive''item-1''item-0'

    或运算

    通过在路径表达式中使用"|"运算符,可以实现选取若干个路径。

    1. # 选取所有的li和a节点 
    2. print(page.xpath("//li|//a")) 
    3.  
    4. // [at 0x29bb7190ac0>, at 0x29bb7190b00>, at 0x29bb7190f00>, at 0x29bb7190dc0>, at 0x29bb7190fc0>, at 0x29bb7190e00>, at 0x29bb7190f80>, at 0x29bb71b1080>, at 0x29bb71b1040>, at 0x29bb7190cc0>] 

    函数

    xpath内置很多函数。更多函数查看https://www.w3school.com.cn/xpath/xpath_functions.asp。

    contains

    有的时候,class作为选择条件的时候不合适@class='....' 这个是完全匹配,当网页样式发生变化时,class或许会增加或减少像active的class。用contains就能很方便。

    1. print(page.xpath("//*[contains(@class, 'item-inactive')]")) 
    2.  
    3. // [] 

    starts-with

    1. print(page.xpath("//*[starts-with(@class, 'item-inactive')]")) 
    2. // [at 0x1a297641d00>] 

    其他几个函数,我们在上面使用过。注意,并不是所有的 xpath 函数python都会支持,比如 ends-with(string1,string2) 和 upper-case(string) 就不支持。

    节点轴选择

    ancestor轴

    调用 ancestor 轴,获取所有祖先节点。其后需要跟两个冒号,然后是节点的选择器。返回结果:第一个li节点的所有祖先节点。

    1. print(page.xpath('//li[1]/ancestor::*')) 
    2.  
    3. // [, , , ] 

    attribute轴

    调用 attribute 轴,获取所有属性值。返回结果:li节点的所有属性值。

    1. print(page.xpath('//li[1]/attribute::*')) 
    2.  
    3. // ['item-0'

    child轴

    调用 child 轴,获取所有直接子节点。返回结果:选取 href 属性为 link1.html 的 a 子节点。

    1. print(page.xpath('//li[1]/child::a[@href="link1.html"]')) 
    2.  
    3. // [at 0x13972af5b40>] 

    descendant轴

    调用 descendant 轴,获取所有子孙节点。同时加了限定条件。返回结果:选取 li 节点下的子孙节点里的 span 节点。

    1. print(page.xpath('//li[4]/descendant::span')) 
    2.  
    3. // [at 0x1a4d5700d00>] 

    following轴

    调用 following 轴,获取当前节点之后的所有节点。

    1. print(page.xpath('//li[4]/following::*[2]')) 
    2.  
    3. // [at 0x1583f8c0d00>] 

    following-sibling轴

    调用 following-sibling 轴,获取当前节点之后的所有同级节点。

    1. print(page.xpath('//li[4]/following-sibling::*')) 
    2.  
    3. // [] 

    总结

    到这里,我们的 xpath 学习之路就结束了,文章中基本涵盖了大家需要用的的 xpath 解析方法。大家看一遍没记住不要紧,以后遇到此类解析直接搬出这篇文章对照着写就行。

     

    来源:Python技术内容投诉

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    软考中级精品资料免费领

    • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

      难度     813人已做
      查看
    • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

      难度     354人已做
      查看
    • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

      难度     318人已做
      查看
    • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

      难度     435人已做
      查看
    • 2024年上半年系统架构设计师考试综合知识真题

      难度     224人已做
      查看

    相关文章

    发现更多好内容

    猜你喜欢

    AI推送时光机
    位置:首页-资讯-后端开发
    咦!没有更多了?去看看其它编程学习网 内容吧
    首页课程
    资料下载
    问答资讯