ImQi1云笔记ImQi1云笔记
首页
  • 鸿蒙开发
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • Vue.js
  • Java速查
  • Python 速查
  • Python 异步编程
  • Django框架
  • FastAPI
  • Flask框架
  • PyQt6
  • Tornado框架
  • Linux基本命令
  • Linux Shell
  • Git命令速查
  • Docker 学习笔记
  • Nginx 学习笔记
  • MySQL
  • MongoDB
  • Redis
  • XPath
首页
  • 鸿蒙开发
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • Vue.js
  • Java速查
  • Python 速查
  • Python 异步编程
  • Django框架
  • FastAPI
  • Flask框架
  • PyQt6
  • Tornado框架
  • Linux基本命令
  • Linux Shell
  • Git命令速查
  • Docker 学习笔记
  • Nginx 学习笔记
  • MySQL
  • MongoDB
  • Redis
  • XPath
  • XPath

XPath

XPath是一钟确认文档位于XML位置的语言,它同样适用于HTML。它提供了超过100个内置函数、用于字符串、时间、数字的匹配以及序列、节点的处理。现在流行的XPath版本为3.1。

Xpath术语

  1. 节点:XPath中有七种节点:元素节点、属性节点、文本节点、命名空间节点、处理指令节点、注释节点和文档节点。
  2. 父节点、子节点:和DOM中的概念类似。
  3. 同胞节点:若两个节点有相同的父节点,那么它们就互称为同胞节点。

Xpath表达式

最常见的XPath表达式就是路径表达式。路径表达式就是从一个节点到另一个节点或一组节点的书面步骤顺序。这些步骤以“/”字符分开,每一步有三个组成成分:轴描述、节点测试、节点名称。

  1. 简写的XPath表达式

如一个div位于文本中的位置如下:<html><body><div></div><body><html>,那么它的位置使用XPath表示就是/html/body/div。

  1. 完整的XPath表达式

在XPath语法的每个步骤里,用完整的轴描述,然后使用“::”,它的后面跟着节点测试的内容。

  1. 轴描述语法

轴描述元素用于表示HTML文档分支的遍历方向。

坐标名称缩写语法
child子节点默认,不需要
attribute属性@
descendant子孙节点不提供
desendant-or-self自身引用及子孙节点//
parent父节点..
ancestor祖先节点不提供
ancestor-or-self自身引用及祖先节点
following下文节点
preceding前文节点
following-sibiling下一个同级节点
preceding-sibiling上一个同级节点
self自己
namespace名称空间

attribute坐标简写语法的一个范例就是//a/@href,在HTML文档书里,选择所有a元素的href属性。self坐标通常和术语同用,以参考当前的选定节点。如h3[.='See also']在当前节点选中了h3的元素,该元素的内容为See also。

节点测试

节点测试的对象通常包括特定节点名或者一般的表达式。

  1. comment():寻找HTML注释节点。
from lxml import etree

html = """
<p>这是没有注释的内容</p>
<!--这是被注释的内容-->
"""

xp = etree.HTML(html)
print(xp.xpath('//comment()'))
[<!--这是被注释的内容-->]
  1. text():寻找某点的文字型别,例如在<p>Hello</p>节点中寻找Hello。
from lxml import etree

html = """
<p>这是没有注释的内容</p>
<!--这是被注释的内容-->
"""

xp = etree.HTML(html)
print(xp.xpath('//p/text()'))
['这是没有注释的内容']
  1. node():寻找所有节点。
from lxml import etree

html = """
<div><p id='content'>这是没有注释的内容</p>
<!--这是被注释的内容--></div>
"""

xp = etree.HTML(html)
print(xp.xpath('//div/node()'))
[<Element p at 0x2691d7d6300>, '\n', <!--这是被注释的内容-->]

节点描述

节点描述用于返回符合特定条件的节点,如//a[@href='help.php']会选择所有href属性为help.php的a节点,//a[@href='help.php'][name(..)='div'][../@class='header']会返回href属性为help.php、具有父元素div且它的class属性为header的a节点。

XPath运算符

运算符描述示例返回值
|两个节点集并集xpath('//div|//a')返回所有的div元素节点和a节点
+/-/*/div加减乘除xpath('//div[2-1]')返回所有div元素的第一个结果
=等于xpath('//a[href="baidu.com"]')返回所有href值为baidu.com的a元素
!=不等于
</<=/>/>=小于/小于等于/大于/大于等于xpath('//input[@value>2]')返回所有value属性大于2的input元素
or/and或/并且xpath('//input[@value=1 or @value=2]')返回所有value属性等于1或2的input元素
mod取余

练手:

from lxml import etree

html = """<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Xpath教程</title>
</head>
<body>
<ul>
    <li><a href="www.likeinlove.com/index.html">出师未捷身先死,长使英雄泪满襟。</a></li>
    <li><a href="www.likeinlove.com/home.html">风急天高猿啸哀,渚清沙白鸟飞回。</a></li>
    <li>仲夏苦夜短,开轩纳微凉。</li>
    <!--    以上是杜甫部分名句-->
</ul>
<p id="4">万里悲秋常作客,百年多病独登台。</p>
<p id="5">清江一曲抱村流,长夏江村事事幽。</p>
<div>
    <ul>
        <li>满月飞明镜,归心折大刀。</li>
        <li>射人先射马,擒贼先擒王。</li>
        <li>留连戏蝶时时舞,自在娇莺恰恰啼。</li>
        <li>正是江南好风景,落花时节又逢君。</li>
    </ul>
</div>
</body>
</html>
"""

xp = etree.HTML(html)
print('获取标题内容',xp.xpath('//title/text()'))
print('获取页面语言',xp.xpath('//html/@lang'))
print('获取页面超链接',xp.xpath('//a/@href'))
print('获取id为4的诗句',xp.xpath('//p[@id=4]/text()'))
获取标题内容 ['Xpath教程']
获取页面语言 ['en']
获取页面超链接 ['www.likeinlove.com/index.html', 'www.likeinlove.com/home.html']
获取id为4的诗句 ['万里悲秋常作客,百年多病独登台。']

XPath常用函数

函数作用示例
contains(string1, string2)若string1包含string2,返回Truexpath('//a[contains(@href, "baidu")]')
starts-with(string1, string2)若string1以string2看开始,返回Truexpath('//a[starts-with(@href, "baidu")]')
substring(string, start, len)截取字符串string,start代表起始位置,第一个字符的下标为1,len可省略,表示截取到末尾xpath('//a[substring(@href,1,5)="https"]')
string-length(string)返回指定字符串的长度,若string不填写则返回当前节点的字符串的长度xpath('//a[string-length(@href)=18]')
position()返回当前正在被处理的节点的index位置xpath('//*[@value=3][posotion()=2]')
last()返回在被处理的节点哄的项目数目xpath('//li[last()=3]')
true()返回True
false()返回False
name(nodeset)指定节点集中的第一个节点的名称,若不传参数则为当前节点名称xpath('//*name()="div"')
count(nodeset)返回节点的数量xpath(//p[count(//p)=3])

XPath常见错误

  • Unregistered Function:未注册该函数。
  • Invalid Predicate:无效谓词。
  • Unfinished Literal:表达式不完整。

使用Python解析HTML

Python解析HTML的库有lxml、BeautifulSoup4、pyquery等。第一个主要提供XPath语法的选择器,第二个则依赖Python标准库,提供了节点选择器,第三个提供CSS选择器。

使用这以下的代码分别安装这三个模块。

pip install lxml
pip install bs4
pip install pyquery

下面的代码将尝试用这三个库提取如下HTML代码中的这段话。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>标题</title>
</head>
<body>
<p>这是网页中的一段话。</p>
</body>
</html>
  1. lxml
#/html/body/p
from lxml import etree

html = """<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>标题</title>
</head>
<body>
<p>这是网页中的一段话。</p>
</body>
</html>"""

xp = etree.HTML(html)
items = xp.xpath('//html//body//p//text()')
print(items)
['这是网页中的一段话。']
  1. BeautifulSoup4
#/html/body/p
from bs4 import BeautifulSoup

html = """<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>标题</title>
</head>
<body>
<p>这是网页中的一段话。</p>
</body>
</html>"""

bs = BeautifulSoup(html, 'lxml')
items = bs.select('p')
print(items)
[<p>这是网页中的一段话。</p>]
  1. pyquery
from pyquery import PyQuery as query

html = """<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>标题</title>
</head>
<body>
<p>这是网页中的一段话。</p>
</body>
</html>"""

pq = query(html)
items = pq('p')
print(items)
<p>这是网页中的一段话。</p>
上次更新: