条条XPATH通罗马

如果说正则表达式是暴力美学,万物皆可匹配,那么Xpath更像是针对XML文档的一把手术刀,精准的帮你一层层剥开XML文档修饰的外壳,直达元素所在。

XPath(XML Path Language) 是一门在 XML 文档中查找信息的语言。XML 指可扩展标记语言(Extensible Markup Language)。

XML 被设计用来传输和存储数据,不用于表现和展示数据,HTML 则用来表现数据。

但现在也可用于HTML文档的搜索。

下面我们通过python的lxml库,使用Xpath对HTML进行解析

lxml库是第三方库需要进行安装:

1
pip install lxml

在使用lxml库时我们这样调用,使用其中的etree模块:

1
from lxml import etree

注意在引用etree时编译器可能会表上红色下划线,但其实程序可以正常运行,并不会报错,如果想要解决的话可以这样写:

1
2
from lxml import html
etree=html.etree

安装完成后我们就可以开始进行XPath的学习了。

XML文档和HTML文档可以看成一颗树,上面有许多的节点,下面给出XPath解析该树的一些常用规则(摘自菜鸟教程)

选取节点

表达式 描述
nodename 选取此节点的所有子节点。
/ 从根节点选取(取子节点)。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置(取子孙节点)。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。
路径表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。

是不是还没开始就感觉很复杂,不用担心,如果你要找的节点不是网页后期JavaScript渲染上去的,那么你可以这样获得其XPath路径:

右键检查

image-20230228231322042

点击圈起来的按钮

image-20230228231441798

鼠标移到想要选中的元素上,单击

image-20230228231801224

鼠标移到网页源码上的阴影区域,右键”复制”,”复制XPath”就可以啦。

当然,现在大部分的网站都会进行JS渲染,很多元素我们都是不能直接在网页源代码里找到的,所以这种方法我们目前还不是很用的到。下面我们正式开始使用XPath解析HTML文档。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!Doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>XML 语法 | 菜鸟教程</title>

<meta name='robots' content='max-image-preview:large' />
<link rel='stylesheet' id='classic-theme-styles-css' href='http://www.runoob.com/wp-includes/css/classic-themes.min.css?ver=1' type='text/css' media='all' />
<link rel="canonical" href="http://www.runoob.com/xml/xml-syntax.html" />
<meta name="keywords" content="XML 语法">
<meta name="description" content="XML 语法规则 XML 的语法规则很简单,且很有逻辑。这些规则很容易学习,也很容易使用。 XML 文档必须有根元素 XML 必须包含根元素,它是所有其他元素的父元素,比如以下实例中 root 就是根元素: [mycode3 type=&#039;xml&#039;] ..... [/mycode3] 以下实例中 note 是根元素: [mycode3 type=&#039;xml&#039;..">

<link rel="shortcut icon" href="https://static.runoob.com/images/favicon.ico">
<link rel="stylesheet" href="/wp-content/themes/runoob/style.css?v=1.170" type="text/css" media="all" />
<link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" media="all" />
<!--[if gte IE 9]><!-->
<script src="https://cdn.staticfile.org/jquery/2.0.3/jquery.min.js"></script>
<!--<![endif]-->
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<![endif]-->
<link rel="apple-touch-icon" href="https://static.runoob.com/images/icon/mobile-icon.png"/>
<meta name="apple-mobile-web-app-title" content="菜鸟教程">
</head>

这是菜鸟教程网页的一部分源码,我们想要把他变成可供XPath解析的HTML文档,有以下两种方式:

一.将str类型的text转为HTML

1
2
3
text="<head>......</head>"

html=etree.HTML(text)

二.将代码存在test.html文件里

1
htmel=etree.parse('./test.heml',etree.HTMLParser)

转化完毕之后,我们就需要按上述的规则来解析HTML文档了。

和一般的树一样,HTML节点树的节点之间也有一下几种关系:父节点,子节点,先辈节点,后代节点,我们正是以此为依据来一点一点的解析节点树来获得我们所要的内容的。

所有节点

我们通常使用//来获得所有符合要求的节点,如果我们想要获得所有节点,可以:

1
2
result=html.xpath('//*')
print(result)

结果:

image-20230301001455649

得到了所有的节点。*代表对节点无限制条件,返回的结果是一个列表,列表里的元素均是Element类型,后面跟着节点的名字。

子节点

子节点或者子孙节点我们可以使用/或//来获得,其中/获得的是当前节点的直接子节点,而//获得的是当前节点的所有子孙结点。例如我们获取第一层的所有子节点:

1
result=html.xpath('/*')

结果为:

image-20230301081519838

只有一个节点,也就是第一层的html节点。

而使用//*则能获得第一层往下的所有子孙节点,也就是所有的节点。

父节点

想要查找上一层的父节点也很简单,我们可以使用..来完成,

1
2
3
result=html.xpath('//meta[@name="keywords"]')
result=result[0].xpath("..")
print(result)

这段代码中我们先找了name属性为keywords的meta节点,再寻找他的父亲节点,结果如下;

image-20230301112720948

得到了head节点

我们同样可以使用parent::来寻找父亲节点:

1
2
3
result=html.xpath('//meta[@name="keywords"]')
result=result[0].xpath("parent::*")
print(result)

属性匹配

XPath语法中,采用@来匹配节点的属性值以进行筛选

1
2
result=html.xpath('//meta[@name]')
print(result)

上述代码筛出了所有含有name属性的meta节点,结果如下

image-20230301114051765

但如果仅仅这样去筛选的话,范围太大了,所以我们需要对具体属性的值进行筛选:

1
2
result=html.xpath('//meta[@name="robots"]')
print(result)

结果为:

image-20230301190834237

就定位到了

image-20230301190959434

这个meta节点,注意定位时属性值要加上””或’’。

如果你在匹配值是有多个节点属性值相同,那么就不能在使用上面的方法了

文本获取

在网络爬虫中,我们往往关注的是标签里的文本内容,例如

1
<div class="tab"  id="cate0"><i class="fa fa-reorder"></i> 全部教程</div>

我们想要获取div节点中所夹的”全部教程”四字,可以使用text()方法:

1
2
txt=html.xpath('//text()')
print(txt)

image-20230301193250578

属性获取

属性的获取和属性的匹配其实有点像,只不过少去了[]方括号,

还是用上面的div节点为例,我们要获得i节点的class属性,可以这样:

1
2
class_value=html.xpath('//i/@class')
print(class_value)

image-20230301195428121

后面还有一些复杂的操作,本章篇幅有限,我们以后再做讨论,Thanks♪(・ω・)ノ

End~~ 撒花ฅ>ω<*ฅ花撒