Loading

Xpath 使用技巧

简介

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>&#213;&#226;&#192;&#239;&#202;&#199;&#184;&#246;&#208;&#161;&#177;&#234;&#204;&#226;</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版
posted @ 2020-09-21 18:00  kingron  阅读(1052)  评论(0编辑  收藏  举报