Python爬虫从入门到进阶(4)之xpath的使用
官网地址:https://lxml.de/xpathxslt.html
导入:
from lxml import etree
lxml.tree 支持 ElementTree 和 Element 上的 find,findall,findtext方法的简单路径语法,作为特定的 lxml 扩展,这些类提供了 xpath()方法,该方法支持完整xpath语法中的表达式,以及定制的扩展函数。
xpath()方法
对于ElementTree,xpath 方法对文档(绝对路径)或者根节点执行全局(相对路径) xpath查询
def demo_1():
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
r = tree.xpath('/foo/bar')
print(len(r))
print(r[0].tag) r_2 = tree.xpath('bar')
print(r_2[0].tag)
在 Element 上使用 xpath() 时,xpath()表达式根据元素(相对路径)或根树(绝对路径)查询:
def demo_2():
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f) root = tree.getroot()
r = root.xpath('bar')
print(r[0].tag) bar = root[0]
r = bar.xpath('/foo/bar')
print(r[0].tag)
xpath()方法支持xpath变量:
def demo_3():
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
root = tree.getroot() expr = "//*[local-name() = $name]"
print(root.xpath(expr, name='foo')[0].tag)
print(root.xpath(expr, name="bar")[0].tag)
print(root.xpath("$text", text="Hello World!"))
命名空间和前缀
如果XPath表达式使用名称空间前缀,则必须在前缀映射中定义它们。为此,将一个字典传递给namespace关键字参数,该参数将XPath表达式中使用的名称空间前缀映射到名称空间uri
def demo_4():
f = StringIO('''\
<a:foo xmlns:a="http://codespeak.net/ns/test1"
xmlns:b="http://codespeak.net/ns/test2">
<b:bar>Text</b:bar>
</a:foo>
''') doc = etree.parse(f)
r = doc.xpath('/x:foo/b:bar',
namespaces={'x': 'http://codespeak.net/ns/test1',
'b': 'http://codespeak.net/ns/test2'})
print(len(r))
print(r[0].tag)
print(r[0].text)
在这里选择的前缀并没有连接到XML文档中使用的前缀,文档可以定义任何前缀,包括空前缀,也不会破坏上面的代码
注意 XPath 没有默认的命名空间,因此,XPath 中没有定义空前缀,不能在命名空间前缀映射中使用
XPath返回值
XPath返回值的类型取决于使用的Xpath 表达式:
(1) True 或者 False
(2) float
(3) “智能的”string
XPath字符串的结果是“智能的”,因为它们提供了一个getparent()方法,该方法知道它们的起源:
(i)对于属性值,result.getparent()返回携带它们的元素。例如//foo/@attribute,它的父元素是一个foo元素。
(ii)对于text()函数(如//text()),它返回包含返回的文本或尾部的元素。
以使用布尔属性is_text、is_tail和is_attribute来区分不同的文本源。
注意,getparent()不一定总是返回一个元素。例如,XPath函数string()和concat()将构造没有原点的字符串。对于它们,getparent()将不返回任何值。
有些情况下 smart string 并不受欢迎。例如:它意味着树将字符串保持活动状态,如果字符串值是树中唯一真正需要的东西,那么它可能会对内存产生相当大的影响。对于这些情况,可以使用关键字 smart_strings禁用父关系
def demo_5():
root = etree.XML("<root><a>TEXT</a></root>")
find_text = etree.XPath("//text()")
text = find_text(root)[0]
print(text)
print(text.getparent().text) # 禁用父关系
find_text = etree.XPath("//text()", smart_strings=False)
text = find_text(root)[0]
print(text)
hasattr(text, 'getparent')
(4) list 或者 items
生成XPath表达式
ElementTree对象有一个getpath(element)方法,它返回一个结构的、绝对的XPath表达式来查找该元素:
def demo_6():
a = etree.Element("a")
b = etree.SubElement(a, "b")
c = etree.SubElement(a, "c")
d1 = etree.SubElement(c, "d")
d2 = etree.SubElement(c, "d")
tree = etree.ElementTree(c)
print(tree.getpath(d2)) # /c/d[2]
print(tree.xpath(tree.getpath(d2)) == [d2])
XPath类
XPath类将XPath表达式编译为可调用函数
def demo_7():
root = etree.XML("<root><a><b/></a><b/></root>")
find = etree.XPath("//b")
print(find(root)[0].tag)
编译花费的时间和 xpath()方法相同,但是每个类实例化编译一次,这能提高重复计算相同 Xpath 表达式的效率。就像xpath()方法一样,XPpath类支持xpath变量
def demo_8():
root = etree.XML("<root><a><b/></a><b/></root>")
count_elements = etree.XPath("count(//*[local-name() = $name])")
print(count_elements(root, name="a"))
print(count_elements(root, name="b"))
这支持非常有效地计算XPath表达式的修改版本,因为编译仍然只需要一次。
前缀到命名空间的映射可以作为第二个参数传递:
def demo_9():
root = etree.XML("<root xmlns='NS'><a><b/></a><b/></root>")
find = etree.XPath("//n:b", namespaces={'n': 'NS'})
print(find(root)[0].tag)
XPath中的正则表达式
默认情况下,XPath支持EXSLT名称空间中的正则表达式,也可以使用 regexp 关键字禁用它,默认值是 True
def demo_10():
regexpNS = "http://exslt.org/regular-expressions"
find = etree.XPath("//*[re:test(., '^abc$', 'i')]", namespaces = {'re': regexpNS})
root = etree.XML("<root><a>aB</a><b>aBc</b></root>")
print(find(root)[0].text)
后面还有一些看不下去了,下一篇写下 xpath 的常规用法,点击下载代码
Python爬虫从入门到进阶(4)之xpath的使用的更多相关文章
- Python 爬虫从入门到进阶之路(八)
在之前的文章中我们介绍了一下 requests 模块,今天我们再来看一下 Python 爬虫中的正则表达的使用和 re 模块. 实际上爬虫一共就四个主要步骤: 明确目标 (要知道你准备在哪个范围或者网 ...
- Python 爬虫从入门到进阶之路(二)
上一篇文章我们对爬虫有了一个初步认识,本篇文章我们开始学习 Python 爬虫实例. 在 Python 中有很多库可以用来抓取网页,其中内置了 urllib 模块,该模块就能实现我们基本的网页爬取. ...
- Python爬虫从入门到进阶(1)之Python概述及爬虫入门
一.Python 概述 1.计算机语言概述 (1).语言:交流的工具,沟通的媒介 (2).计算机语言:人跟计算机交流的工具 (3).Python是计算机语言的一种 2.Python编程语言 代码:人类 ...
- Python 爬虫从入门到进阶之路(六)
在之前的文章中我们介绍了一下 opener 应用中的 ProxyHandler 处理器(代理设置),本篇文章我们再来看一下 opener 中的 Cookie 的使用. Cookie 是指某些网站服务器 ...
- Python 爬虫从入门到进阶之路(九)
之前的文章我们介绍了一下 Python 中的正则表达式和与爬虫正则相关的 re 模块,本章我们就利用正则表达式和 re 模块来做一个案例,爬取<糗事百科>的糗事并存储到本地. 我们要爬取的 ...
- Python 爬虫从入门到进阶之路(十二)
之前的文章我们介绍了 re 模块和 lxml 模块来做爬虫,本章我们再来看一个 bs4 模块来做爬虫. 和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也 ...
- Python 爬虫从入门到进阶之路(十五)
之前的文章我们介绍了一下 Python 的 json 模块,本章我们就介绍一下之前根据 Xpath 模块做的爬取<糗事百科>的糗事进行丰富和完善. 在 Xpath 模块的爬取糗百的案例中我 ...
- Python 爬虫从入门到进阶之路(十六)
之前的文章我们介绍了几种可以爬取网站信息的模块,并根据这些模块爬取了<糗事百科>的糗百内容,本章我们来看一下用于专门爬取网站信息的框架 Scrapy. Scrapy是用纯Python实现一 ...
- Python 爬虫从入门到进阶之路(十七)
在之前的文章中我们介绍了 scrapy 框架并给予 scrapy 框架写了一个爬虫来爬取<糗事百科>的糗事,本章我们继续说一下 scrapy 框架并对之前的糗百爬虫做一下优化和丰富. 在上 ...
随机推荐
- 吐血总结|史上最全的MySQL学习资料!!
在日常工作与学习中,无论是开发.运维.还是测试,对于数据库的学习是不可避免的,同时也是日常工作的必备技术之一.在互联网公司,开源产品线比较多,互联网企业所用的数据库占比较重的还是MySQL. 在刚刚出 ...
- 哈尔滨工业大学(威海)第九届ACM程序设计竞赛 Virtual Youtuber
链接 [https://ac.nowcoder.com/acm/contest/624/G] 题意 其实题意说的辣鸡死了,没有说明确. y is the subsequences that its s ...
- EntityFramework Core笔记:保存数据(4)
1. 基本保存 每个DBContext实例都有一个ChangeTracker,负责跟踪需要写入数据库的更改.当实例发生更改时,更改会被记录在ChangeTracker中,在调用 SaveChanges ...
- vue cli使用融云实现聊天
公司有个项目要实现一个聊天功能,需求如下图,略显随意 公司最终选择融云这个吊炸天的即时通信,文档详细的一匹,刚开始看文档感觉很详细实现起来也不麻烦,有很多开源的demo可以在线演示和下载 不过我们的项 ...
- .Net Core 环境下构建强大且易用的规则引擎
本文源码: https://github.com/jonechenug/ZHS.Nrules.Sample 1. 引言 1.1 为什么需要规则引擎 在业务的早期时代,也许使用硬编码或者逻辑判断就可以满 ...
- python的排序方式
""" 冒泡排序: 冒泡排序的思想: 每次比较两个相邻的元素, 如果他们的顺序错误就把他们交换位置 比如有五个数: 12, 35, 99, 18, 76, 从大到小排序, ...
- JSON.stringify的三个参数(转载)
前段时间勾股有提到stringify是支持三个参数,刷新的了我的认知,后来查到文档才发现还真的是支持三个参数的. 参考资料: stringify stringify方法顾名思义,就是把JSON序列换, ...
- [PRIMITIVE TECHNOLOGY]澳洲小哥的黑皮豆/black been/摩顿湾板栗(栗子)/Moreton Bay Chestnut
wiki:https://en.wikipedia.org/wiki/Castanospermum inner:http://blog.sciencenet.cn/blog-309517-770951 ...
- P1282 多米诺骨牌 (背包变形问题)
题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点.现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|.例如在图8-1中,S1=6+1+1+1=9, ...
- 数位DP::SoSDP
数位DP:: SoSDP 学习博客(待补) 下面做一些例题: SPECIAL PAIRS 题意 给n个数字,求这些数字有多少对的\(AND\) 结果是0.数字不大于1e6.顺序反相反视为不同的对. 思 ...