Xpath(from lxml import etree)
一些比较好的教程网站分享:
W3School_Xpath教程
菜鸟教程_Xpath语法
1、准备工作
- 安装:
pip install lxml
- 搭配的Xpath Helper工具
下载地址:Xpath_helper 提取码:6666
2、基本使用
- Xpaht全称 XML路径语言(XML Path Language),可以在XML文档中获取元素或者属性信息。
- etree.HTML():将一个简单的字符串转换成
<class 'lxml.etree._Element'>
对象 - etree.tostring():将一个
<class 'lxml.etree._Element'>
对象转换成字符串并修正HTML代码结构 - 以下代码是简单的使用案例:
# etree.HTML():将一个简单的字符串转换成<class 'lxml.etree._Element'>对象
from lxml import etree
text = '<h2>这里是一个测试</h2>'
html = etree.HTML(text)
title = html.xpath('//h2/text()')[0] # 获取h2标签下的文字
print(title)
# etree.tostring():将一个<class 'lxml.etree._Element'>对象转换成字符串并修正HTML代码结构
from lxml import etree
text = '<h2>这里是一个测试</h2>'
html = etree.HTML(text)
result = etree.tostring(html, encoding='utf-8')
print(type(result.decode()), result.decode())
html = etree.HTML(result.decode())
print(type(html))
title = html.xpath('//h2/text()')[0] # 获取h2标签下的文字
print(title)
3、Xpath常用规则
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从根节点选取(取子节点) |
// | 从匹配的节点中选择子节点(不需要考虑位置) |
. | 选取当前节点 |
. . | 选取当前节点的父节点 |
@ | 选取属性 |
* | 匹配任何元素节点 |
@* | 匹配任何属性节点 |
node() | 匹配任何类型的节点 |
4、Xpath常用实例
更多详细会持续更新,下列所示是我暂时工作中比较常用到的。
- .xpath(‘//*’):代表匹配所有节点,返回类型为列表,列表里面每一个元素都是_Element类型。
- .xpath(‘//li’):代表匹配当前源代码下所有li节点元素
- .xpath(‘//li/a’):代表匹配当前源代码下所有li节点下的a节点元素
- .xpath(‘//li[@class=“item_2”]’):代表匹配当前源代码下所有li节点下的class为item_2的节点元素
- .xpath(‘//li[@class=“item_3”]/a/text()’):代表匹配当前源代码下所有li节点下的class为item_3的节点元素下的a元素的文本
- .xpath(‘//li[@class=“item_3”]/a/@href’):代表匹配当前源代码下所有li节点下的class为item_3的节点元素下的a元素的href属性
- .xpath(‘//li/p[@id=“p4”]/…/@name’):代表匹配当前源代码下p节点下的id为p4元素节点的父节点li的class中name属性
- .xpath(‘//li[contains(@class, “t4”)]/p/text()’):代表匹配当前源代码下li的class包含t4下的p标签的文本数据
- .xpath(‘//li[contains(text(), “测试”)]/text()’):代表匹配当前源代码下li的class=test下的文本数据是否是测试
- .xpath(‘//li[contains(@class, “t4”) and @name=“n4”]/p/text()’):代表匹配当前源代码下li的class包含t4并且name=n4下的p元素节点的文本数据
- .xpath(‘//li[@class=“test”]/text() | //li[@class=“item”]/text()’):代表匹配当前源代码下li的class=test并且class=item下的文本数据
from lxml import etree
html_text = '''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Xpath练习实例</title>
</head>
<body>
<div id="demo">
<ul>
<li class="item">demo_test_1</li>
<li class="item_2">demo_test_2</li>
<li class="item_3"><a href="https://www.baidu.com">demo_test_3</a></li>
<li class="t4 item" name="n4"><p id="p4">demo_test_4</p></li>
<li class="test">测试</li>
</ul>
</div>
</body>
</html>'''
html = etree.HTML(html_text)
result = html.xpath('//*') # 代表匹配当前源代码下的所有节点
print(result)
result = html.xpath('//li') # 代表匹配当前源代码下所有li节点元素
print(result)
result = html.xpath('//li/a') # 代表匹配当前源代码下所有li节点下的a节点元素
print(result)
result = html.xpath('//li[@class="item_2"]') # 代表匹配当前源代码下所有li节点下的class为item_2的节点元素
print(result)
result = html.xpath('//li[@class="item_3"]/a/text()') # 代表匹配当前源代码下所有li节点下的class为item_3的节点元素下的a元素的文本
print(result)
result = html.xpath('//li[@class="item_3"]/a/@href') # 代表匹配当前源代码下所有li节点下的class为item_3的节点元素下的a元素的href属性
print(result)
result = html.xpath('//li/p[@id="p4"]/../@name') # 代表匹配当前源代码下p节点下的id为p4元素节点的父节点li的class中name属性
print(result)
result = html.xpath('//li[contains(@class, "t4")]/p/text()') # 代表匹配当前源代码下li的class包含t4下的p标签的文本数据
print(result)
result = html.xpath('//li[contains(text(), "测试")]/text()') # 代表匹配当前源代码下li的class=test下的文本数据是否是测试
print(result)
result = html.xpath('//li[contains(@class, "t4") and @name="n4"]/p/text()') # 代表匹配当前源代码下li的class包含t4并且name=n4下的p元素节点的文本数据
print(result)
5、Xpath按序选择
Xpath选择大致能分成三大类:正序选择、倒序选择、范围选择
- 正序选择
- .xpath(“//li[1]/a/text()”):选取第一个li节点,中括号中传入数字1即可。
注意,这里和代码中不同,序号是以1开头的,不是以0开头的
- .xpath(“//li[1]/a/text()”):选取第一个li节点,中括号中传入数字1即可。
- 倒序选择
- .xpath(“//li[last()]/a/text()”):选取最后一个li节点,中括号中传入last()即可
- .xpath(“//li[last()-1]/a/text()”):选取倒数第二个li节
- .xpath(“//li[last()-2]/a/text()”):选取倒数第三个li节
- 范围选择
- .xpath(“//li[position()<= 3]/a/text()”):选择位置小于等于3的li节点
from lxml import etree
html_text = '''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Xpath练习实例2</title>
</head>
<body>
<div id="demo">
<ul>
<li class="item"><a href="#">demo_test_1</a></li>
<li class="item_2"><a href="#">demo_test_2</a></li>
<li class="item_3"><a href="https://www.baidu.com">demo_test_3</a></li>
<li class="t4 item" name="t4"><a href="#">demo_test_4</a></li>
<li class="item"><a href="#">测试s</a></li>
</ul>
</div>
</body>
</html>'''
html = etree.HTML(html_text)
result = html.xpath("//li[1]/a/text()") # 选取第一个li节点,中括号中传入数字1即可
print(result)
result = html.xpath("//li[last()]/a/text()") # 选取最后一个li节点,中括号中传入last()即可
print(result)
result = html.xpath("//li[last()-1]/a/text()") # 选取倒数第二个li节
print(result)
result = html.xpath("//li[last()-2]/a/text()") # 选取倒数第三个li节
print(result)
result = html.xpath("//li[position()<= 3]/a/text()") # 选择位置小于等于3的li节点
print(result)
6、Xpath节点轴选择
- Xpath还提供了很多节点轴选择方法,例如获取子元素、获取父元素、获取兄弟元素等
- 有关节点轴的节点集如下:
轴名称 | 结果 |
---|---|
ancestor | 选取当前节点的所有先辈(父、祖父等)。 |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。 |
attribute | 选取当前节点的所有属性。 |
child | 选取当前节点的所有子元素。 |
descendant | 选取当前节点的所有后代元素(子、孙等)。 |
descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
following | 选取文档中当前节点的结束标签之后的所有节点。 |
following-sibling | 选取当前节点之后的所有兄弟节点 |
namespace | 选取当前节点的所有命名空间节点。 |
parent | 选取当前节点的父节点。 |
preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
preceding-sibling | 选取当前节点之前的所有同级节点。 |
self | 选取当前节点。 |
from lxml import etree
html_text = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Xpath练习实例3</title>
</head>
<body>
<div id="demo">
<ul>
<li class="item"><a href="#"><span>demo_test_1</span></a></li>
<li class="item_2"><a href="#" id="d2">demo_test_2</a><a href="#">1111</a></li>
<li class="item_3"><a href="https://www.baidu.com">demo_test_3</a></li>
<li class="t4 item" name="t4"><a href="#">demo_test_4</a></li>
<li class="item"><a href="#">测试s</a></li>
</ul>
</div>
</body>
</html>'''
html = etree.HTML(html_text)
result = html.xpath('//li[1]/a/span/ancestor::*') # 调用ancestor获取当前节点的所有父辈,祖先
print(result)
result = html.xpath('//li[1]/a/span/ancestor-or-self::*') # 调用ancestor-or-self获取当前节点的所有父辈,祖先,包括自己
print(result)
result = html.xpath('//li[1]/a/span/ancestor::div') # 调用ancestor获取只有div的祖先节点
print(result)
result = html.xpath('//li[last()-1]/attribute::*') # 调用attribute获取当前节点的所有属性
print(result)
result = html.xpath('//li[2]/child::*') # 调用child获取当前节点的所有子元素
print(result)
result = html.xpath('//li[2]/child::a[@id="d2"]') # 调用child获取当前节点的所有子元素中选中的元素
print(result)
result = html.xpath('//li[1]/descendant::*') # 调用descendant获取当前节点的所有后代元素
print(result)
result = html.xpath('//li[1]/following::*[2]/text()') # 调用following轴,获取当前节点之后的所有节点,这里我们虽然使用的是*匹配,但又加了索引选择,所以只获取了第二个后续节点
print(result)
result = html.xpath('//li[1]/following-sibling::*') # 调用following-sibling轴,获取当前节点之后的所有兄弟节点
print(result)
result = html.xpath('//li[1]/namespace::*') # 调用namespace轴,获取当前节点所有命名空间节点
print(result)
result = html.xpath('//li[1]/parent::*') # 调用parent轴,获取当前节点的父亲节点
print(result)
result = html.xpath('//li[1]/preceding::*') # 调用preceding轴,获取Head的所有节点
print(result)
result = html.xpath('//li[3]/preceding-sibling::*') # 调用preceding-sibling轴,获取当前节点之前的所有同级节点
print(result)
result = html.xpath('//li[last()]/a/self::*/text()') # 调用self轴,获取当前节点的数据
print(result)
总结
以上便是我觉得xpath技术在实际工作中比较常用的方法,其中可能还会有欠缺,如果在接下来的实际操作中,有用到其他的案例,也会继续在这里进行添加。当然如果文章中有不对的地方,欢迎评论区留言进行指导,我会及时更改。