pythonxpath教程_花了半天时间整理了xpath最详细的全面教程!拿去用吧

使用时先安装 lxml 包

开始使用

和beautifulsoup类似,首先我们需要得到一个文档树

把文本转换成一个文档树对象

from lxml import etree

if __name__ == '__main__':

doc='''

'''

html = etree.HTML(doc)

result = etree.tostring(html)

print(str(result,'utf-8'))

把文件转换成一个文档树对象

from lxml import etree

# 读取外部文件 index.html

html = etree.parse('./index.html')

result = etree.tostring(html, pretty_print=True)    #pretty_print=True 会格式化输出

print(result)

均会打印出文档内容

节点、元素、属性、内容

xpath 的思想是通过 路径表达 去寻找节点。节点包括 元素,属性,和内容

元素举例

html ---> ...

div --->

...

a  ---> ...

这里我们可以看到,这里的 元素和html中的标签一个意思。单独的元素是无法表达一个路径的,所以单独的元素不能独立使用

路径表达式

/  根节点,节点分隔符,

//  任意位置

.  当前节点

..  父级节点

@  属性

通配符

*  任意元素

@*  任意属性

node()  任意子节点(元素,属性,内容)

谓语

使用中括号来限定元素,称为谓语

//a[n] n为大于零的整数,代表子元素排在第n个位置的元素

//a[last()]  last()  代表子元素排在最后个位置的元素

//a[last()-]  和上面同理,代表倒数第二个

//a[position()<3] 位置序号小于3,也就是前两个,这里我们可以看出xpath中的序列是从1开始

//a[@href]    拥有href的元素

//a[@href='www.baidu.com']    href属性值为'www.baidu.com'的元素

//book[@price>2]  price值大于2的元素

多个路径

用 |连接两个表达式,可以进行或匹配

//book/title | //book/price

函数

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

contains(string1,string2)

starts-with(string1,string2)

ends-with(string1,string2) #不支持

upper-case(string) #不支持

text()

last()

position()

node()

可以看到last()也是个函数,在前面我们在谓语中已经提到过了

案例

定位元素

匹配多个元素,返回列表

from lxml import etree

if __name__ == '__main__':

doc='''

'''

html = etree.HTML(doc)

print(html.xpath("//li"))

print(html.xpath("//p"))

【结果为】

[, , , , ]

[]  #没找到p元素

html = etree.HTML(doc)

print(etree.tostring(html.xpath("//li[@class='item-inactive']")[0]))

print(html.xpath("//li[@class='item-inactive']")[0].text)

print(html.xpath("//li[@class='item-inactive']/a")[0].text)

print(html.xpath("//li[@class='item-inactive']/a/text()"))

print(html.xpath("//li[@class='item-inactive']/.."))

print(html.xpath("//li[@class='item-inactive']/../li[@class='item-0']"))

【结果为】

b'

third item\n                '

None    #因为第三个li下面没有直接text,None

third item  #

['third item']

[]

[, ]

使用函数

contains

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

from lxml import etree

if __name__ == '__main__':

doc='''

first item

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

'''

html = etree.HTML(doc)

print(html.xpath("//*[contains(@class,'item')]"))

【结果为】

[, , , , ]

starts-with

from lxml import etree

if __name__ == '__main__':

doc='''

first item

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

'''

html = etree.HTML(doc)

print(html.xpath("//*[contains(@class,'item')]"))

print(html.xpath("//*[starts-with(@class,'ul')]"))

【结果为】

[, , , , , ]

[]

ends-with

print(html.xpath("//*[ends-with(@class,'ul')]"))

【结果为】

Traceback (most recent call last):

File "F:/OneDrive/pprojects/shoes-show-spider/test/xp5_test.py", line 18, in

print(html.xpath("//*[ends-with(@class,'ul')]"))

File "src\lxml\etree.pyx", line 1582, in lxml.etree._Element.xpath

File "src\lxml\xpath.pxi", line 305, in lxml.etree.XPathElementEvaluator.__call__

File "src\lxml\xpath.pxi", line 225, in lxml.etree._XPathEvaluatorBase._handle_result

lxml.etree.XPathEvalError: Unregistered function

看来python的lxml并不支持有的xpath函数列表

upper-case

和ends-with函数一样,也不支持。同样报错 lxml.etree.XPathEvalError: Unregistered function

print(html.xpath("//a[contains(upper-case(@class),'ITEM-INACTIVE')]"))

text、last

#最后一个li被限定了

print(html.xpath("//li[last()]/a/text()"))

#会得到所有的``元素的内容,因为每个标签都是各自父元素的最后一个元素。

#本来每个li就只有一个子元素,所以都是最后一个

print(html.xpath("//li/a[last()]/text()"))

print(html.xpath("//li/a[contains(text(),'third')]"))

【结果为】

['fifth item']

['second item', 'third item', 'fourth item', 'fifth item']

[]

position

print(html.xpath("//li[position()=2]/a/text()"))

#结果为['third item']

上面这个例子我们之前以及讲解过了

* 这里有个疑问,就是 position()函数能不能像text()那样用呢

print(html.xpath("//li[last()]/a/position()"))

#结果  lxml.etree.XPathEvalError: Unregistered function

这里我们得到一个结论,函数不是随意放在哪里都能得到自己想要的结果

node

返回所有子节点,不管这个子节点是什么类型(熟悉,元素,内容)

print(html.xpath("//ul/li[@class='item-inactive']/node()"))

print(html.xpath("//ul/node()"))

【结果为】

[]

['\n                ', , '\n                ', , '\n                ', , '\n                ', , '\n                ', , ' 闭合标签\n            ']

获取内容

**刚刚已经提到过,可以使用 .text和text()的方式来获取元素的内容

from lxml import etree

if __name__ == '__main__':

doc='''

'''

html = etree.XML(doc)

print(html.xpath("//a/text()"))

print(html.xpath("//a")[0].text)

print(html.xpath("//ul")[0].text)

print(len(html.xpath("//ul")[0].text))

print(html.xpath("//ul/text()"))

【结果为】

['first item', 'second item', 'third item', 'fourth item', 'fifth item']

first item

18

['\n                ', '\n                ', '\n                ', '\n                ', '\n                ', ' 闭合标签\n            ']

看到这里,我们观察到 text()和.text的区别。自己总结吧。不太好表达,就不表达了

获取属性

print(html.xpath("//a/@href"))

print(html.xpath("//li/@class"))

【结果为】

['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']

['item-0 active', 'item-1', 'item-inactive', 'item-1', 'item-0']

自定义函数

我们从使用函数的过程中得到结论,就是有的函数不支持,有的支持,那问题来了,到底那些方法支持呢。我们在lxml官网找到了答案。 https://lxml.de/xpathxslt.html 。lxml 支持XPath 1.0 ,想使用其他扩展,使用libxml2,和libxslt的标准兼容的方式。 XPath 1.0官方文档 以及其他版本的XPath文档 https://www.w3.org/TR/xpath/

lxml supports XPath 1.0, XSLT 1.0 and the EXSLT extensions through libxml2 and libxslt in a standards compliant way.

除此之外,lxml还提供了自定义函数的方式来扩展xpath的支持度 https://lxml.de/extensions.html

from lxml import etree

#定义函数

def ends_with(context,s1,s2):

return s1[0].endswith(s2)

if __name__ == '__main__':

doc='''

'''

html = etree.XML(doc)

ns = etree.FunctionNamespace(None)

ns['ends-with'] = ends_with #将ends_with方法注册到方法命名空间中

print(html.xpath("//li[ends-with(@class,'active')]"))

print(html.xpath("//li[ends-with(@class,'active')]/a/text()"))

【结果为】

[, ]

['first item', 'third item']

形参 s1会传入xpath中的第一个参数@class,但这里注意@class是个列表

形参 s2会传入xpath中的第二个参数'active','active'是个字符串

官网例子 https://lxml.de/extensions.html

706f41d49920

def hello(context, a):

return "Hello %s" % a

from lxml import etree

ns = etree.FunctionNamespace(None)

ns['hello'] = hello

root = etree.XML('Haegar')

print(root.xpath("hello('Dr. Falken')"))

# 结果为 Hello Dr. Falken

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值