专栏首页codingxpath库详解xpath入门获取所有节点 //子节点 /父节点 ..属性匹配 @文本获取按序选择节点轴选择

xpath库详解xpath入门获取所有节点 //子节点 /父节点 ..属性匹配 @文本获取按序选择节点轴选择

xpath入门

python爬虫抓取网页内容,需要对html或xml结构的数据进行解析,如果用正则,单是写正则表达式就让很多望而生畏了。

这个问题可以用正则表达式处理,于是,一个问题就变成了两个问题

对于我们这些不喜欢写正则的人来说,xpath提供了更方便的解析数据功能。

xpath全称是:XML Path Language, 见名知意,是专门用于解析结构性语言的

xpath常用规则

使用xpath之前要先安装lxml库

pip install lxml

入门示例:

from lxml import etree

text = '''
<div>
    <ul>
        <li class="item-0"><a href="link1.html">first</a></li>
        <li class="item-1"><a href="link2.html">second</a>
        <li class="item-2"><a href="link3.html">third</li>
        <li class="item-3"><a href="link4.html">fourth</a></li>
    </ul>
</div>
'''

html = etree.HTML(text)
result = etree.tostring(html)
print(result.decode('utf-8'))

注意查看代码中的html片段,第二个li没有闭合,第三个li的a标签没有闭合

查看结果:

<html><body><div>
    <ul>
        <li class="item-0"><a href="link1.html">first</a></li>
        <li class="item-1"><a href="link2.html">second</a>
        </li><li class="item-2"><a href="link3.html">third</a></li>
        <li class="item-3"><a href="link4.html">fourth</a></li>
    </ul>
</div>
</body></html>

可以看到,etree模块不仅将缺少的标签闭合了,而且还加上了html、body节点

还可以读取文本内容进行解析

新建 test.html

<div>
    <ul>
        <li class="item-0"><a href="link1.html">first</a></li>
        <li class="item-1"><a href="link2.html">second</a></li>
        <li class="item-2"><a href="link3.html">third</a></li>
        <li class="item-3"><a href="link4.html">fourth</a></li>
    </ul>
</div>
from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = etree.tostring(html)
print(result.decode('utf-8'))

结果:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><div>
    <ul>
        <li class="item-0"><a href="link1.html">first</a></li>
        <li class="item-1"><a href="link2.html">second</a></li>
        <li class="item-2"><a href="link3.html">third</a></li>
        <li class="item-3"><a href="link4.html">fourth</a></li>
    </ul>
</div>
</body></html>

获取所有节点 //

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//*')
print(result)

结果:

[<Element html at 0x1085a5e88>, <Element body at 0x1085a5f88>, <Element div at 0x1085a5fc8>, <Element ul at 0x1085c9048>, <Element li at 0x1085c9088>, <Element a at 0x1085c9108>, <Element li at 0x1085c9148>, <Element a at 0x1085c9188>, <Element li at 0x1085c91c8>, <Element a at 0x1085c90c8>, <Element li at 0x1085c9208>, <Element a at 0x1085c9248>]

//* 表示匹配所有节点

匹配指定节点,如获取所有li节点

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li')
print(result)  # 所有li节点
print(result[0])  # 第一个li节点

结果:

[<Element li at 0x110115f88>, <Element li at 0x110115fc8>, <Element li at 0x110139048>, <Element li at 0x110139088>]
<Element li at 0x110115f88>

子节点 /

获取li节点的直接子节点

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a') # 获取所有li节点的直接子节点a
print(result)
[<Element a at 0x103c02f88>, <Element a at 0x103c02fc8>, <Element a at 0x103c26048>, <Element a at 0x103c26088>]

改成 // 可以这么写:

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//div//a')  # 获取div的所有后代a节点
print(result)

父节点 ..

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
# 获取href属性为link2.html的a标签的父节点的class名
result = html.xpath('//a[@href="link2.html"]/../@class')

print(result)
# ['item-1']

属性匹配 @

根据属性值匹配节点

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
# 获取属性class值为item-0的li
result = html.xpath('//li[@class="item-0"]')

print(result)
# [<Element li at 0x10c2b1f88>]

获取属性值

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
# 获取所有li的子节点a的属性href
result = html.xpath('//li/a/@href')

print(result)
# ['link1.html', 'link2.html', 'link3.html', 'link4.html']

属性多值匹配

使用contains函数匹配

from lxml import etree

text = '''
<li class="li li-first"><a href="link.html">first item</a></li>
'''

html = etree.HTML(text)
result = html.xpath('//li[@class="li"]/a/text()')
print(result)
# []

result = html.xpath('//li[contains(@class, "li")]/a/text()')
print(result)
# ['first item']

多属性匹配

需要匹配满足多个属性的节点,使用 and 运算符

from lxml import etree

text = '''
<li class="li li-first" name="item"><a href="link.html">first item</a></li>
'''

html = etree.HTML(text)
# 通过class和name两个属性进行匹配
result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
print(result)
# ['first item']

xpath的运算符介绍

运算符

文本获取

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
# 获取属性class值为item-0的li的子节点a的文本内容
result = html.xpath('//li[@class="item-0"]/a/text()')

print(result)
# ['first']

如果想要获取后代节点内部的所有文本,使用 //text()

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
# 获取所有li的后代节点中的文本
result = html.xpath('//li//text()')

print(result)
# ['first', 'second', 'third', 'fourth']

按序选择

根据节点所在的顺序进行提取

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())

# 按索引排序
result = html.xpath('//li[1]/a/text()')
print(result)
# ['first']

# last 最后一个
result = html.xpath('//li[last()]/a/text()')
print(result)
# ['fourth']

# position 位置查找
result = html.xpath('//li[position()<3]/a/text()')
print(result)
# ['first', 'second']

# - 运算符
result = html.xpath('//li[last()-2]/a/text()')
print(result)
# ['second']

节点轴选择

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())

# 所有祖先节点
result = html.xpath('//li[1]/ancestor::*')
print(result)
# [<Element html at 0x106e4be88>, <Element body at 0x106e4bf88>, <Element div at 0x106e4bfc8>, <Element ul at 0x106e6f048>]

# 祖先节点中的div
result = html.xpath('//li[1]/ancestor::div')
print(result)
# [<Element div at 0x106ce4fc8>]

# 节点的所有属性
result = html.xpath('//li[1]/attribute::*')
print(result)
# ['item-0']

# 子节点
result = html.xpath('//li[1]/child::a[@href="link1.html"]')
print(result)
# [<Element a at 0x107941fc8>]

# 后代节点中的a
result = html.xpath('//li[1]/descendant::a')
print(result)
# [<Element a at 0x10eeb7fc8>]

# 该节点后面所有节点中的第2个 从1开始计数
result = html.xpath('//li[1]/following::*[2]')
print(result)
# [<Element a at 0x10f188f88>]

# 该节点后面的所有兄弟节点
result = html.xpath('//li[1]/following-sibling::*')
print(result)
# [<Element li at 0x104b7f048>, <Element li at 0x104b7f088>, <Element li at 0x104b7f0c8>]

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • pyquery 库详解安装pyquery 介绍数据初始化基本css选择器查找节点遍历节点获取属性获取文本节点操作伪类选择器

    虽然 xpath 与 Beautiful Soup 已经很强大了,不过语法还是过于啰嗦,pyquery提供了更加简洁优雅的语法,你可以像写jquery一般提取数...

    章鱼喵
  • vue.js动画中的js钩子函数

    在transition中还可以通过设置javascript钩子函数,实现自定义动画效果。

    章鱼喵
  • Beautiful Soup库详解安装Beautiful Soup 介绍节点选择器方法选择器css 选择器

    只需要在初始化 Beautiful Soup 时,将第二个参数设置为 lxml 即可

    章鱼喵
  • 杨校老师课堂之Web前端JS类库_JQuery案例[效果图与代码齐全]

    下载:https://files.cnblogs.com/files/xiaoxiao5016/font-awesome.min.css  或者官方下载:htt...

    杨校
  • 分享一个纯CSS样式,显示不同颜色数字的排行榜列表

    声明:本文由w3h5原创,转载请注明出处:《分享一个纯CSS样式,显示不同颜色数字的排行榜列表》 https://www.w3h5.com/post/241.h...

    德顺
  • Python-数据解析-lxml库-下

    ElementTree 类中附带了一个类似于 XPath 路径语言的 ElementPath 类。

    小团子
  • Python3解析库lxml

    lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高 XPath,全称XML Path Language...

    菲宇
  • python3解析库lxml

    lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高

    嘘、小点声
  • python基础之list列表的增删改查以及循环、嵌套

    Python的列表在JS中又叫做数组,是基础数据类型之一,以[]括起来,以逗号隔开,可以存放各种数据类型、嵌套的列表、对象。列表是有序的,即有索引值,可切片,方...

    爱学习的孙小白
  • 从零开始学 Web 之 DOM(四)节点

    页面中的所有内容,包括标签,属性,文本(文字,空格,回车,换行等),也就是说页面的所有内容都可以叫做节点。

    Daotin

扫码关注云+社区

领取腾讯云代金券