写点什么

Python 操作 lxml 库与 Xpath

  • 2022-11-27
    北京
  • 本文字数:4983 字

    阅读完需:约 16 分钟

Python 操作 lxml库与Xpath

(爬取网页指定内容)


软件测试工作中常用

1.Python lxml 库介绍

lxml 是 XML 和 HTML 的解析器,其主要功能是解析和提取 XML 和 HTML 中的数据;lxml 和正则一样,也是用 C 语言实现的,是一款高性能的 python HTML、XML 解析器,也可以利用 XPath 语法,来定位特定的元素及节点信息


HTML 是超文本标记语言,主要用于显示数据,他的焦点是数据的外观 XML 是可扩展标记语言,主要用于传输和存储数据,他的焦点是数据的内容

1.1 安装 lxml 模块库

pip install lxml
复制代码

1.2 lxml 是什么

lxml 是以 Python 语言编写的库,主要用于解析和提取 HTML 或者 XML 格式的数据,它不仅功能非常丰富,而且便于使用,可以利用 XPath 语法快速地定位特定的元素或节点。


lxml 库中大部分的功能都位于 lxml.etree 模块中,导入 lxml.etree 模块的常见方式如下:


from lxml import etree
复制代码


lxml 库的一些相关类如吓:●Element 类 :可以理解为 XML 的节点。●ElementTree 类 :可以理解为一个完整的 XML 文档树。●ElementPath 类 :可以理解为 XPath ,于搜索和定位节点。

1.2.1 Element 类简介

Element 类是 XML 处理的核心类,可以直观地理解为 XML 的节点,大部分 XML 节点的处理都是围绕着该类进行的。要想创建一个节点对象,则可以通过构造函数直接创建,示例如下:


root = etree.Element('root')
复制代码


上述示例中,参数 root 表示节点的名称。


关于 Element 类的相关操作,主要可分为三个部分,分别是节点操作、节点属性的操作、节点内文本的操作,下面进行逐一介绍。


1. 节点操作


若要获取节点的名称,则可以通过 tag 属性获取,示例如下:


print(root.tag)# 输出结果如下root
复制代码


2. 节点属性的操作


在创建节点的同时,可以为节点增加属性。节点中的属性是以“key-value”的形式进行存储的,类似于字典的存储方式。通过构造方法创建节点时,可以在该方法中以参数的形式设置属性,其中参数的名称表示属性的名称,参数的值表示为属性的值。创建属性的示例如下:


# 创建root节点,并为其添加属性root = etree.Element('root', interesting='totally')print(etree.tostring(root))# 输出结果如下b'<root interesting="totally"/>'
复制代码


此外,可以通过 set()方法给已有的节点添加属性。在调用该方法时可以传入两个参数,其中第一个参数表示属性的名称,第二个参数表示属性的值,示例如下:


# 再次给root节点添加age属性root.set('age', '30')print(etree.tostring(root))# 输出结果如下b'<root interesting="totally" age="30"/>'
复制代码


在上述两个示例中,都用到了 tostring()函数,该函数可以将元素序列化为其 XML 树的编码字符串表示形式。


3. 节点内文本的操作


一般情况下,可以通过 text、tail 属性或者 xpath()方法来访问文本内容。通过 text 属性访问节点的示例如下:


root = etree.Element('root') # 创建root节点root.text = 'Hello, World!'  # 给root节点添加文本print(root.text)print(etree.tostring(root))# 输出结果如下Hello, World!b'<root>Hello, World!</root>'
复制代码

1.2.2 从字符串或文件中解析 XML

为了能够将 XML 文件解析为树结构,etree 模块中提供了如下三个函数:


  • fromstring()函数:从字符串中解析 XML 文档或片段,返回根节点(或解析器目标返回的结果)。

  • XML()函数:从字符串常量中解析 XML 文档或片段,返回根节点(或解析器目标返回的结果)。

  • HTML()函数:从字符串常量中解析 HTML 文档或片段,返回根节点(或解析器目标返回的结果)。


其中,XML()函数的行为类似于 fromstring()函数,通常用于将 XML 字面量直接写入到源代码中,HTML()函数可以自动补全缺少的< html>和< body>标签。关于上述三个函数的示例如下:


xml_data = '<root>data</root>'# fromstring方法root_one = etree.fromstring(xml_data)print(root_one.tag)print(etree.tostring(root_one))# XML方法,与fromstring方法基本一样root_two = etree.XML(xml_data)print(root_two.tag)print(etree.tostring(root_two))# HTML方法,如果没有<html>和<body>标签,会自动补上root_three = etree.HTML(xml_data)print(root_three.tag)
复制代码


上述示例运行的结果如下:


rootb'<root>data</root>'rootb'<root>data</root>'html
复制代码


除了上述三个函数之外,还可以调用 parse()函数从 XML 文件中直接解析。在调用函数时,如果没有提供解析器,那么就使用默认的解析器,函数会返回一个 ElementTree 类型的对象,示例如下:


html = etree.parse('./hello.html')result = etree.tostring(html, pretty_print=True)print(result)
复制代码

1.2.3 ElementPath 类简介

ElementTree 类中附带了一个类似于 XPath 路径语言的 ElementPath 类。在 ElementTree 类或 Elements 类的 API 文档中,提供了三个常用的方法,可以满足大部分搜索和查询需求,并且这两个方法的参数都是 XPath 语句,具体如下:


  • find()方法:返回匹配到的第一个子元素;

  • findall()方法:以列表的形式返回所有匹配的子元素。

  • iterfind()方法:返回一个所有匹配元素的迭代器。


从文档树的根节点开始,搜索符合要求的节点,示例如下:


# 从字符串中解析XML,返回根节点root = etree.XML("<root><a x='123'>aText<b/><c/><b/></a></root>")# 从根节点查找,返回匹配到的节点名称print(root.find("a").tag)# 从根节点开始查找,返回匹配到的第一个节点的名称print(root.findall(".//a[@x]")[0].tag)
复制代码


示例的结果如下:


aA
复制代码

2.XPath 介绍

2.1 什么是 XPath

XPath(XML Path Language 的简写)即为 XML 路径语言,用于确定 XML 树结构中某一部分的位置。XPath 技术基于 XML 的树结构,能够在树结构中遍历节点(元素、属性等)。


那么,XPath 是如何查找信息呢?XPath 使用路径表达式选取 XML 文档中的节点或者节点集,这些路径表达式与常规的电脑文件系统中看到的路径非常相似,代表着从一个节点到另一个或者一组节点的顺序,并以“/”字符进行分隔。接下来,通过一张示意图来描述 XPath 的路径表达式,如图 1 所示。



注意:


XPath 不仅能够查询 XML 文档,而且能够查询 HTML 文档。不过,需要先将 HTML 文档转换成 XML 文档,之后使用 XPath 语法查找 HTML 文档的节点或者元素。

2.2 XPath 语法

在 Python 中,XPath 使用路径表达式在文档中进行导航。这个表达式是从某个节点开始,之后顺着文档树结构的节点进一步查找。由于查询路径的多样性,可以将 XPath 的语法按照如下情况进行划分:

2.1.1 选取节点

节点是沿着路径选取的,既可以从根节点开始,也可以从任意位置开始。表 1 列举了 XPath 中用于选取节点的表达式。


表 1 选取节点的表达式


接下来是一些选取节点的示例,具体如下:


  1. 选取节点 bookstore 的所有子节点,表达式如下:


bookstore  
复制代码


  1. 选取根节点 bookstore,表达式如下:


/bookstore 
复制代码


需要注意的是,如果路径以“/”开始,那么该路径就代表着到达某个节点的绝对路径。

  1. 从根节点 bookstore 开始,向下选取属于它的所有 book 子节点,表达式如下:


bookstore/book
复制代码


  1. 从任意位置开始,选取名称为 book 的所有节点,表达式如下:


//book
复制代码


与上一个表达式相比,该表达式不用再说明符合要求的这些节点在文档树中的具体位置。


  1. 在节点 bookstore 的后代中,选取所有名称为 book 的所有节点,而且不用管这些节点位于 bookstore 之下的什么位置,表达式如下:


bookstore//book
复制代码


  1. 使用“@”选取名称为 lang 的所有属性节点,表达式如下:


//@lang
复制代码

2.1.2 谓语(补充说明节点)

谓语是对指路径表达式的附加条件,这些条件都写在方括号中,表示对节点进行进一步筛选,用于查找某个特定节点或者包含某个指定值的节点,具体格式如下。


元素[表达式]
复制代码


接下来,通过一张表来列举一些常用的带有谓语的路径表达式,以及对这些表达式功能的说明,具体如表 2 所示。


表 2 使用谓语的表达式


2.1.3 选取未知节点

XPath 可以使用通配符(*)来选取未知的节点。例如,使用“ *”可以匹配任何元素节点。接下来,通过一张表来列举带有通配符的表达式,具体如表 3 所示。


表 3 带有通配符的表达式


下面是一些使用通配符的示例,具体如下:


  1. 选取 bookstore 元素的所有子元素,表达式如下:


/bookstore/*
复制代码


  1. 选取文档中的所有元素,表达式如下:


//*
复制代码


  1. 选取所有带有属性的 title 元素,表达式如下:


//title[@*]
复制代码

2.1.4 选取若干路径

在路径表达式中可以使用“|”运算符,以选取若干个路径。下面是一些在路径表达式中使用“|”运算符的示例,具体如下:


  1. 选取 book 元素中包含的所有 title 和 price 子元素,表达式如下:


//book/title | //book/price
复制代码


  1. 选取文档中的所有 title 和 price 元素,表达式如下:


//title | //price
复制代码


  1. 选取位于/bookstore/book/路径下的所有 title 元素,以及文档中所有的 price 元素,表达式如下:


/bookstore/book/title | //price
复制代码

2.3.如何获取 XPath

对于没有编码基础的小伙伴来说,可以直接用谷歌浏览器自带的【开发者工具】


来获取网页某个元素的 XPath


//*[@id="kw"]
复制代码


/html/body/div[1]/div[1]/div[5]/div/div/form/span[1]/input
复制代码



3 .实战练习

我们使用一个 HTML 示例文件做为素材来介绍 lxml 库的基本使用,该文件名为 hello.html,内容如下:


<!DOCTYPE html><html lang="en"><!--<head>--><!--    <meta charset="UTF-8">--><!--    <title>XPath实战练习</title>--><!--</head>--><body><div>    <ul>         <li class="item-0"><a href="link1.html">first item</a></li>         <li class="item-1"><a href="link2.html">second item</a></li>         <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>         <li class="item-1"><a href="link4.html">fourth item</a></li>         <li class="item-0"><a href="link5.html">fifth item</a></li>     </ul> </div></body></html>
复制代码



接下来,我们基于上述 HTML 文档,使用 lxml 库中的路径表达式技巧,通过调用 xpath()方法匹配选取到的节点,具体如下:

代码

from lxml import etree
html = etree.parse('hello.html')'''1.获取任意位置的li节点-----//li直接使用“//”从任意位置选取节点li;通过lxml.etree模块的xpath方法,将hello.html文件中与该路径表达式匹配到的列表进行返回,并打印输出,具体代码如下。'''# 查找所有的li节点result = html.xpath('//li')# 1.打印<li>标签的元素集合print("1.<li>标签的元素集合:", result)# 2.打印<li>标签的个数print("2.<li>标签的个数:", len(result))# 3.打印返回结果的类型print("3.返回结果的类型:", type(result))# 4.打印第一个元素的类型print("4.第一个元素的类型:", type(result[0]))
'''2.继续获取< li>标签的class属性-----//li/@class在上个表达式的末尾,使用“/”向下选取节点,并使用“@”选取class属性节点,表达式如下:'''# 5.查找位于li标签的class属性result1 = html.xpath('//li/@class')print("5.查找位于li标签的class属性:", result1)
'''3.获取倒数第二个元素的内容------ //li[last()-1]/a 或者 /li[last()-1]/a]/text()从任意位置开始选取倒数第二个< li>标签,再向下选取标签< a>。如果要获取该标签中的文本,可以使用如下表达式:'''# 6.获取倒数第二个元素的内容result = html.xpath('//li[last()-1]/a')print("6.获取倒数第二个元素的内容", result[0].text)
复制代码


输出结果


"D:\Program Files1\Python\python.exe" D:/Pycharm-work/pythonTest/打卡/0816.py1.<li>标签的元素集合: [<Element li at 0x2b9d908>, <Element li at 0x2b9da08>, <Element li at 0x2b9da48>, <Element li at 0x2b9da88>, <Element li at 0x2b9dac8>]2.<li>标签的个数: 53.返回结果的类型: <class 'list'>4.第一个元素的类型: <class 'lxml.etree._Element'>5.查找位于li标签的class属性: ['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']6.获取倒数第二个元素的内容 fourth item
Process finished with exit code 0
复制代码

4. 一个 UI 自动化的简单例子

import timeimport seleniumfrom selenium import webdriver
# 1、创建Chrome实例 。driver = webdriver.Chrome()# 2、driver.get方法将定位在给定的URL的网页 。driver.get("https://www.baidu.com/") # get接受url可以是如何网址,此处以百度为例# 3、定位元素# 3.1、用id定位输入框对象,driver.find_element_by_id("kw").send_keys("python")# 3.2、用id定位点击对象,用click()触发点击事件driver.find_element_by_id('su').click()# 延迟3秒time.sleep(3)# 4、退出访问的实例网站。driver.quit()
复制代码


发布于: 刚刚阅读数: 6
用户头像

一边做一边变得优秀,加油呀 2022-09-19 加入

大家好,我是小鱼新人来报道哈。 CSDN,阿里云专家.....

评论

发布
暂无评论
Python 操作 lxml库与Xpath_11月月更_度假的鱼🐟_InfoQ写作社区