Xpath 使用技巧
阅读原文时间:2023年07月08日阅读:1

XPathXML Path Language,一门在XMLHTML文档中查找信息的语言。

插件安装:

Chrome浏览器插件安装:XPath Helper

火狐浏览器插件安装:try XPath

选取节点

XPath使用路径表达式来选取XML文档中的节点(集)。

表达式

描述

示例

nodename

选取此节点的所有子节点

div

//

查找所有子元素

//div

/

查找直接子元素

/div

.

选取当前节点

./div

..

选取当前节点的父节点

../div

@

选取某个节点的属性

div[@id]

谓语

谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。常见谓语表达式如下:

表达式

描述

备注

/div/div[1]

选取div下的第一个div元素

xpath下标是从1开始的

/div/div[last()]

选取div下的最后一个div元素

/div/div[position()>3]

选取div下的前两个div元素

//div[@id]

选取所有拥有id属性的div元素

//div[@id="10"]

选取所有id为10的div元素

//div[contains(@class, "price")]

选取所有class包含price的div元素

模糊匹配

通配符

*表示通配符

通配符

描述

示例

结果

*

匹配任意节点

/div/*

选取div下的所有子元素

@*

匹配节点中的任何属性

//div[@*]

选取所有带有属性的div元素

选取多个路径

通过在表达式中使用|运算符,可以选取多个路径。示例:

'//div[@class="financial"] | //div[@class="john"]'

运算符

在所有使用的谓词中或选取节点时,可以使用运算符精确的选取节点

运算符

描述

实例

返回值

|

计算两个节点

//div | //dd

返回所用拥有div和dd元素的节点集

+

加法

6+4

10

-

减法

6-4

2

*

乘法

6*4

24

div

除法

8 div 2

4

=

等于

price=9

如果是,返回True,否则返回False

!=

不等于

price!=9

同上

<

小于

price<9

同上

>=

小于或等于

price<=9

同上

or

price=9 or price=10

有一个为真则返回True

and

price=9 and price=10

同为真则返回True

mod

计算除法的余数

5 mod 2

1

比如要选取一个div节点,它的class"financial"id"john",可以使用//div[@class="financail" and id="john"]表达式。在某些拥有同一属性名和内容的元素中选取某个元素比较有用。

使用contains选取包含属性

# div节点包含某个字符串的父节点下的td子节点
'//div[contains(text(), "标签文字包含某个字符串"]/../td'

使用tostring()将对象转换为字符串

# 使用xpath定位一个节点
s = html.xpath('//*[@id="testid"]')[0]
# s此时为<Element div at 0x2b6ffc8>对象
# 还原这个对象为html字符串
s2 = etree.tostring(s)
# s2现为:'<div id="testid">\n\t\t<h2>ÕâÀïÊǸöС±êÌâ</h2>\n\t\t<ol>\n\t\t\t<li data="one">1</li>\n\t\t\t<li data="two">2</li>\n\t\t\t<li data="three">3</li>\n\t\t</ol>\n\t\t<ul>\n\t\t\t<li code="84">84</li>\n\t\t\t<li code="104">104</li>\n\t\t\t<li code="223">223</li>\n\t\t</ul>\n\t</div>\n\t'

使用starts-with

'//div[starts-with(@class, "text")]'

使用not排除属性

# 排除包含某个属性的节点
'//tbody/tr[not(@class)]'
# 排除包含一个或两个属性的节点
'//tbody/tr[not(@class or @id)]'

选取倒数第二个标签

# 定位语法: position()=last()-1

'//tr[@bgcolor="#FFFFFF"]/td[position()=last()-1]//a'

使用 normalize-space

# normalize-space 函数删除了前部和尾部的空格, 并且把连续的空格串替换为一个单一的空格

'//*[starts-with(normalize-space(text()), "数读《共建“一带一路”倡议:进展、贡献和展望")]'

选取某个节点的兄弟节点

使用 preceding-sibling选取之前的兄弟节点,following-sibling选取之后的兄弟节点,例如:

# 选取 class 为 prompt 的 div 节点前的所有 class 为 post 的同级 div 节点
r.xpath('//div[@class="prompt"]/preceding-sibling::div[@class="post"]')

# 选取 class 为 prompt 的 div 节点后的第一个兄弟节点
r.xpath('//div[@class="prompt"]/following-sibling::div[1]')

根据节点名字选取

节点名字可使用 name() 变量获取:

# 选取 div 下所有不是 p 标签的标签
r.xpath('//div/*[name()!="p"]')

选取祖先节点

使用 ancestor::

# 选取文本为 “办公电话” 的标签的 td 祖先标签的父级标签下的第二个子 td 标签下的文字
r.xpath('string(//*[text()="办公电话"]/ancestor::td/../td[2])')

更多

参考:

lxml库的使用

lxml是一个HTML/XML的解析器,解析和提取网页中的数据。它和正则一样,也是通过C语言实现的,是一款高性能的解析器。

用法示例

from lxml import etree

# 对字符串进行解析,同response对象
text = "some web source text..."
html = etree.HTML(text)
# 此时information是一个列表对象(xpath函数返回的永远是一个列表),要选取具体的数据需要给出下标
information = html.xpath('//div[@id="john"]//text()')
# 打印第一个
print(information[0])

# 对网页文件进行解析
html_element = etree.parse('somefile.html')
html = etree.tostring(html_element, encoding='utf-8').decode('utf-8')

备注

  1. etree.parse方法中的parser参数可以传递解析器,如果不指定默认为XML解析器,如果遇到不规范的HTML代码导致解析错误,可以自己创建HTML解析器;
  2. 获取文本通过text()方法,获取属性通过@属性名方法;
  3. 在某个标签下,再执行xpath函数获取子元素,应该在斜杠前加一个.,代表是从当前元素下获取,如./a[@class="test"]

参考

  1. Python爬虫:Xpath语法笔记
  2. lxml官方文档
  3. 【爬虫】xpath高级用法
  4. lxml官方文档-pdf版