Python 爬虫之 XPath 元素定位

XPath 简介

XPath (XML Path Language) 最初是为了在 XML 文档中进行导航而设计的语言,后来被广泛应用于 HTML 文档的解析。与 BeautifulSoup 相比,XPath 有以下特点:

  • 语法强大:可以通过简洁的表达式精确定位元素
  • 跨平台性:几乎所有编程语言都有 XPath 的实现
  • 灵活性高:可以通过各种轴、谓词和函数构建复杂的选择条件

在 Python 中,我们主要通过 lxml 或者 selenium 库来使用 XPath 功能。可以通过 pip 安装下面的依赖包。

pip install lxml
pip install selenium

XPath 测试工具

浏览器

用浏览器测试验证 XPath 最直观,最方便,优先推荐这种方式。比如在百度热搜 百度热搜 测试 XPath。

在浏览器开发者工具的 Elements 中按 Ctrl + F,在搜索框中输入 XPath 。比如查找百度热搜标题,XPath 正确的话,会在页面高亮显示对应的元素。

lxml 

Python 的 lxml 库提供了强大的 XPath 支持。比如以下用来解析提取热搜新闻标题。

from lxml import etree
import requests# 获取HTML内容
url = "https://top.baidu.com/board?tab=realtime"
response = requests.get(url)
html_text = response.text# 解析HTML
# html = etree.HTML(html_text)
# 或者从文件加载HTML
html = etree.parse('百度热搜.html', etree.HTMLParser())# 使用XPath提取数据
titles = html.xpath('//div/a/div[@class="c-single-text-ellipsis"]/text()')  # 获取标题文本
for index, title in enumerate(titles):print(f"第 {index + 1} 条新闻;新闻标题:{title}")
print("===热搜标题提取正常===")
第 1 条新闻;新闻标题:去“三好”邻邦家做客
第 2 条新闻;新闻标题:拜登:特朗普太掉价了
第 3 条新闻;新闻标题:央行1万亿元大红包对普通人影响多大
...
第 48 条新闻;新闻标题:世界人形机器人运动会将在北京举办
第 49 条新闻;新闻标题:苹果探索在浏览器中加入AI搜索功能
第 50 条新闻;新闻标题:专家解读:为何央行此时宣布降准降息
第 51 条新闻;新闻标题:骑士G2冤死 裁判报告公布三次漏判
===热搜标题提取正常===

selenium

Python 的 selenium 库提也供了强大的 XPath 支持。比如使用 RPA 流程自动化爬取数据的时候,总避免不了通过 XPath 去定位和查询元素。以下用来解析提取热搜新闻标题。

from selenium import webdriver
from selenium.webdriver.common.by import Bydef init_driver():option = webdriver.ChromeOptions()driver = webdriver.Chrome(r'./driver/chromedriver.exe', options=option)driver.maximize_window()return driverdef main():driver = init_driver()url = r'file:///E:\lky_project\tmp_project\百度热搜.html'driver.get(url)try:xpath_titles = '//div/a/div[@class="c-single-text-ellipsis"]'titles = driver.find_elements(By.XPATH, xpath_titles)for index, title in enumerate(titles):print(f"第 {index + 1} 条新闻;新闻标题:{title.text}")print("===热搜标题提取正常===")except Exception as e:print("===热搜标题提取报错===", e)returnif __name__ == '__main__':main()
第 1 条新闻;新闻标题:去“三好”邻邦家做客
第 2 条新闻;新闻标题:拜登:特朗普太掉价了
第 3 条新闻;新闻标题:央行1万亿元大红包对普通人影响多大
...
第 48 条新闻;新闻标题:世界人形机器人运动会将在北京举办
第 49 条新闻;新闻标题:苹果探索在浏览器中加入AI搜索功能
第 50 条新闻;新闻标题:专家解读:为何央行此时宣布降准降息
第 51 条新闻;新闻标题:骑士G2冤死 裁判报告公布三次漏判
===热搜标题提取正常===

XPath 常用函数 

contains()

contains() 函数用于判断某个属性的取值中是否包含指定的字符串。其语法格式如下:

contains(@attribute, "substring")
    • @attribute:表示要过滤的属性名称,属性名称前需加上@符号。
    • substring:表示要判断是否包含的字符串。

    在自动化测试中,contains 函数特别适用于定位那些属性值不固定的元素。例如,某个元素的id 属性值在每次页面刷新时都会发生变化,但其中某些字符是固定的。通过 contains 函数,可以基于这些固定的字符进行定位。

    比如页面中查找 name 属性中包含 username 的 input 元素:

    //input[contains(@name, 'username')]

    starts-with()

    与 contains() 类似,只不过是限定指定开头的属性或者文本。

    //div/a/div[starts-with(text(), "  国防部")]

    ends-with()

    限定指定结尾的属性或者文本(部分浏览器不一定支持,要想兼容性更强的话建议最好少用)

    //div/a/div[ends-with(text(), "热烈欢迎 ")]

    position()

    position() 函数用于选取指定位置的元素。其语法格式如下。

    //element[position() < number]
    //element[position() <= number]
    //element[position() = number]
    //element[position() > number]
    //element[position() >= number]
    • position():表示元素的序号,从1开始计数。
    • number:表示设定的阈值。

    比如:

    //element[1]

    等价于:

    //element[position() = 1]

     比如页面中有多个 input 元素,我们希望选取前两个 input 元素。

    //input[position()<3]

    last()

    last() 函数用于选取从后往前数的元素。其语法格式如下:

    //element[last() - number]
    
      • last():表示匹配元素的总数。
      • number:表示从后往前数的元素位置。

      假设页面中有多个 input 元素,我们希望选取最后一个 input 元素:

      //input[last()]
      

        如果希望选取倒数第二个 input 元素:

        //input[last() - 1]

        count() 

        count() 函数通过对子元素指定类型节点进行统计来限定父元素的选取。语法格式如下:

        //element[count(sub_element) < number]
        //element[count(sub_element) <= number]
        //element[count(sub_element) = number]
        //element[count(sub_element) > number]
        //element[count(sub_element) >= number]
        • count(sub_element):表示 element 元素 下 sub_element 的数目。
        • number:表示设定的阈值。

         比如我们选取子元素中 div 的个数为 2 的 a 元素:

        //a[count(div)=2] 

        text()

        text() 函数用于获取元素的直接文本内容。一般与 contains() 结合使用,来选取文本内容包含指定字符串的元素。

        比如查找文本中包含 "热烈欢迎" 的 div 元素。

        //div[contains(text(), "热烈欢迎")]

        也可以用文本的精确匹配。

        //div[text()="热烈欢迎"]

        node()

        node() 函数用于选取所有节点。其语法格式如下:

        //node()
        

          node()函数的功能与 * 通配符号类似,用于选取所有节点。例如:

          //* 
          或 
          //node()
          

            上述两种表达式的效果相同,均用于选取页面中的所有节点(但通配符 * 不包括文本,注释,指令等节点,如果也要包含这些节点请用 node() 函数)。

            XPath 基础语法

            路径操作符

            操作符描述示例
            /从根节点选取元素/html/body
            //递归步进下降选择文档中符合条件的所有元素//a
            .选取当前节点./div
            ..选取当前节点的父节点../
            @选取属性//div[@id]
            *通配符,选择任意元素//*

            条件谓词

            XPath 允许我们使用方括号 [] 来添加条件谓词进行筛选限定 。

            //div[1]                                # 第一个div元素
            //div[last()]                           # 最后一个div元素
            //div[position()<3]                     # 前两个div元素
            //div[@class]                           # 所有有class属性的div元素
            //div[@class='main']                    # class属性值为'main'的div元素
            //div[contains(@class, 'content')]      # class属性包含'content'的div元素
            //a[text()='click']                     # 文本内容为'click'的a元素
            //a[count(div)=2]                       # 包含2个div元素的a元素

            轴操作

            以 百度热搜 首页为例。

            ancestor

            ancestor 用以获取元素的祖先节点。比如 热搜 对应  xpath 为:

            //div[2]/a/span[text()="热搜"]

            则下面的 xpath 用以获取 热搜 元素对应的所有祖先节点:

            //div[2]/a/span[text()="热搜"]/ancestor::*

            包含当前节点自身则需要用 ancestor-or-self: 

            //div[2]/a/span[text()="热搜"]/ancestor-or-self::*

            则下面的 xpath 用以获取 热搜 元素对应的所有 div 祖先节点:

            //div[2]/a/span[text()="热搜"]/ancestor::div

            descendant

            descendant 用以获取元素的后代节点。

            比如获取 //div[@id="sanRoot"] 的所有后代 div 节点(不限定节点类型则使用 *)

            //div[@id="sanRoot"]/descendant::div

            包含当前节点自身则需要用 decendant-or-self: 

            //div[@id="sanRoot"]/descendant-or-self::div

            following

            following 用以选取文档中当前节点结束标签之后的所有节点。

            //div/div[@class="bg-wrapper"]/following::*

            如果只选取当前节点之后的所有兄弟节点,则使用 following-sibling。

            //div/div[@class="bg-wrapper"]/following-sibling::*

            preceding

            preceding 用于选取文档中当前节点开始标签之前的所有节点(不包含当前节点的父辈节点)。

            //div[last()]/div[@class="content_1YWBm"]/preceding::*

            如果选取当前节点之前的所有同级节点,则使用 preceding-sibling。

            //div[last()]/div[@class="content_1YWBm"]/preceding-sibling::*

            parent

            parent 用以获取元素的父节点。

            //div/div[@class="bg-wrapper"]/parent::*

            child

            child 用以获取元素的子节点。

            //div/div[@id="sanRoot"]/child::*

            self 

            self 用以获取当前元素节点自己本身。

            //div/div[@id="sanRoot"]/self::*

            attribute 

            通过属性来获取元素。

            比如获取所有包含 class 属性的节点。

            //attribute::class
            或
            //@class

            获取所有包含 class 属性的 div 节点。

             //div[@class]

            逻辑运算符

            and

            逻辑与,比如查询热搜的前三个热搜。

            //div/div[@class="category-wrap_iQLoo horizontal_1eKyQ" and position()<4]

            or

            逻辑或

            //div/div[@class="category-wrap_iQLoo horizontal_1eKyQ" or position()=last()]

            not

            //div/a/div[not(@class="c-single-text-ellipsis")]

            XPath 优化

            一般可以在浏览器中直接复制 XPath,但是浏览器复制的 XPath 一般是用绝对路径写的能唯一定位这个元素的 XPath。 如果页面结构稍微发生变动,可能导致 XPath 不可用。

            比如复制的 XPath 如下:

            //*[@id="sanRoot"]/main/div[2]/div/div[2]/div[1]/div[2]/a/div[1]

            优化后可以为: 

            //div[1]/div/a/div[@class="c-single-text-ellipsis"]

             XPath 常用的优化思路包括:

            • 找到元素附近的独特标识(如 id、特定的 class 等)
            • 尽量使用相对路径而非绝对路径
            • 使用 contains() 等函数处理动态变化的属性值

            本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/80352.shtml

            如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

            相关文章

            聊聊自动化办公未来趋势

            1. 自动化办公未来趋势 1.1 智能化与AI融合加深 随着人工智能技术的不断成熟&#xff0c;其在自动化办公中的应用将更加广泛和深入。未来&#xff0c;办公软件将具备更强的智能交互能力&#xff0c;能够理解自然语言指令&#xff0c;自动完成复杂的任务&#xff0c;如文档编辑…

            智慧工会服务平台建设方案Word(23页)

            1. 引言 随着信息技术的快速发展&#xff0c;传统工会服务模式面临挑战&#xff0c;智慧工会服务平台应运而生。该平台旨在通过数字化手段&#xff0c;整合工会资源&#xff0c;优化服务流程&#xff0c;提高工作效率&#xff0c;为会员提供更加便捷、高效、个性化的服务体验。…

            React Hooks 深入浅出

            目录 引言&#xff1a;React Hooks 的革命基础 Hooks useState&#xff1a;状态管理的新方式useEffect&#xff1a;组件生命周期的替代方案useContext&#xff1a;简化 Context API 额外的 Hooks useReducer&#xff1a;复杂状态逻辑的管理useCallback 与 useMemo&#xff1a;…

            【应急响应】- 日志流量如何分析?

            【应急响应】- 日志流量如何下手&#xff1f;https://mp.weixin.qq.com/s/dKl8ZLZ0wjuqUezKo4eUSQ

            stm32 debug卡在0x1FFFxxxx

            自己画的一个四轴飞机电路板&#xff0c;之前还能debug&#xff0c;改了一下mos管两端的电阻&#xff0c;还能正常下载&#xff0c;蓝牙接收也正常&#xff0c;但是debug出问题了&#xff0c;刚下载就自动运行&#xff0c;然后程序就在0x1FFFxxxx附近循环运行&#xff0c;这一块…

            java-----------------多态

            多态&#xff0c;当前指的是 java 所呈现出来的一个对象 多态 定义 多态是指同一个行为具有多个不同表现形式或形态的能力。在面向对象编程中&#xff0c;多态通过方法重载和方法重写来实现。 强弱类型语言 javascript 或者python 是弱类型语言 C 语言&#xff0c;或者 C…

            Java 23种设计模式 - 结构型模式7种

            Java 23种设计模式 - 结构型模式7种 1 适配器模式 适配器模式把一个类的接口变换成客户端所期待的另一种接口&#xff0c;从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。 优点 将目标类和适配者类解耦增加了类的透明性和复用性&#xff0c;将具体的实现封…

            Git clone时出现SSL certificate problem unable to get local issuer certificate

            正确解决方法 git config --global http.sslVerify false错误解决方法&#xff1a;&#xff08;主要是看错了嘿嘿&#xff0c;但是如果是 OpenSSL SSL_read: Connection was reset, errno 10054 Failed to connect to github.com port 443: Timed out 原…

            DevExpressWinForms-AlertControl-使用教程

            文章目录 AlertControl-使用教程一、将 AlertControl 添加到 Form二、编辑 AlertControl 的 HtmlTemplateHTML Template Editor介绍编辑HTML Template 三、使用AlertControl弹出AlertAlert中的按钮事件获取 Alert 标题等信息向Alert传递参数 总结源码 AlertControl-使用教程 一…

            制作项目进度表常用的 8 款项目管理工具分享

            在数字化管理和高效协作的今天&#xff0c;项目进度表软件已经成为企业管理不可或缺的工具。无论是中小型企业还是大型机构&#xff0c;都需要通过精准的项目计划和实时的进度跟踪来确保业务目标的顺利达成。这篇文章将聚焦项目进度表软件&#xff0c;深入探讨市场上8款主流产品…

            SecureCRT网络穿透/代理

            场景 公司的办公VPN软件只有Windows系统版本&#xff0c;没有Macos系统版本&#xff0c;而日常开发过程中需要先登录VPN后&#xff0c;然后才能登录应用服务器。 目的&#xff1a;Macos系统在使用SecureCRT时&#xff0c;登录服务器&#xff0c;需要走Parallels Desktop进行网络…

            【计算机网络-传输层】传输层协议-TCP核心机制与可靠性保障

            &#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 上篇文章&#xff1a;传输层协议-UDP 下篇文章&#xff1a; 网络层 我们的讲解顺序是&…

            OpenMagnetic的介绍与使用

            1. Background OM&#xff08;OpenMagnetic&#xff09;OpenMagnetics&#xff0c;能涵盖气隙磁阻&#xff0c;磁导率&#xff0c;铁芯损耗、磁滞损耗、涡流电流损耗、涡流效应、漏感、温升的计算与仿真[1]。 铁损计算模型&#xff1a;改进的Steinmetz方程[2] 气隙阻抗计算&…

            【JVM】从零开始深度解析JVM

            本篇博客给大家带来的是JVM的知识点, 重点在类加载和垃圾回收机制上. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f680; …

            字符串---Spring字符串基本处理

            一、String类的特性 不可变性 String对象一旦创建&#xff0c;内容不可更改&#xff0c;任何修改操作都会生成新对象。字符串常量池 字符串字面量&#xff08;如"abc"&#xff09;直接存储在常量池中&#xff0c;重复字面量共享同一内存地址。创建方式 虽然都是字符…

            26考研——中央处理器_CPU 的功能和基本结构(5)

            408答疑 文章目录 一、CPU 的功能和基本结构CPU 的功能CPU 的基本结构运算器控制器 CPU 的寄存器运算器中的寄存器控制器中的寄存器 八、参考资料鲍鱼科技课件26王道考研书 九、总结 一、CPU 的功能和基本结构 CPU 的功能 中央处理器&#xff08;CPU&#xff09;由运算器和控…

            传统数据展示 vs 可视化:谁更打动人心?

            数据&#xff0c;每天都在我们身边流动&#xff1a;从你手机里的健康步数&#xff0c;到企业财报中的营收增长&#xff0c;再到国家发布的经济指标。但问题是——你怎么“看”这些数据&#xff1f; 过去&#xff0c;我们习惯用表格、文字和报告来展示数据&#xff0c;这种方式…

            Base64 编码原理详细解析

            Base64 编码是一种常见的数据编码方式&#xff0c;它将二进制数据转化为可打印的 ASCII 字符串。Base64 编码广泛应用于电子邮件、URL 编码、HTTP 请求和响应中等场景。它的核心作用是让二进制数据可以通过仅支持文本的协议或媒介进行传输。本文将更深入地探讨 Base64 编码的原…

            一周学会Pandas2 Python数据处理与分析-Pandas2数据排序操作

            锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili Pandas 2提供了多种灵活的数据排序方法&#xff0c;主要针对 DataFrame 和 Series 对象。 1. 按值排序&#xff1a;s…

            计算机二级(C语言)已过

            非线性结构&#xff1a;树、图 链表和队列的结构特性不一样&#xff0c;链表可以在任何位置插入、删除&#xff0c;而队列只能在队尾入队、队头出队 对长度为n的线性表排序、在最坏情况下时间复杂度&#xff0c;二分查找为O(log2n)&#xff0c;顺序查找为O(n)&#xff0c;哈希查…