使用XPath
XPath,全称XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言,它最初是用来搜索XML文档的,但是他同样适用于HTML文档的搜索。
XPath概览
XPath的选择功能十分的强大,他提供了非常简明了的路径选择表达式。另外,它还提供了超过100个内建函数,用于字符串,数值,时间的匹配以及节点,序列的处理等,几乎所有我们想要定位的节点,都可以用XPath来选择。
官方文档:https://www.w3.org/TR/xpath。
XPath常用规则
列举了XPath的几个常用的规则。
表达式 | 描述 |
---|---|
nodename | 选取节点的所有子节点 |
/ | 从当前节点选取直接子节点 |
// | 从当前节点选取子孙节点 |
. | 选取当前节点 |
. . | 选取当前节点的父节点 |
@ | 选取属性 |
这里列出了XPath的常用匹配规则,实例如下:
//title[@lang=‘eng’]
这就是一个XPath规则,他代表选择所有名称为title,同时属性lang的值为eng的节点。
后面会通过Python的lxml库,利用XPath进行HTML的解析。
准备工作
使用之前,首先要确保安装好lxml库。
实例引入
XPath对网页结点惊醒解析。
from lxml import etree
text = '''
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href ="link3.html">third item</a></li>
<li class= "item-1"><a href="link4.html">fourth item</a></li>
<li class= "item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
'''
html = etree.HTML(text)
result = etree.tostring(html)
print(result.decode('utf-8'))
输出结果为:
<html><body><div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</li></ul>
</div>
</body></html>
解析:先导入lxml库中的etree模块,然后声明一段HTML文本,就会后造一个XPath对象,并且etree对模块自动修正HTML文本。
这里调用tostring()方法即可输出修正后的HTML代码。但是结果是bytes类型,这里利用decode()方法将其转成str类型结果如下:
可以看到经过处理后HTML文本中的标签被不全了,并且还添加了body,html结点。
另外也可以直接读取文本文件解析,示例如下:
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 item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</li></ul>
</div>
</body></html>
所有节点
我门一般会用//开头的XPat规则来选取所有符合要求的节点,如果要选取所有的节点可以通过下述代码实现。
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
result = html.xpath('//*')
print(result)
输出结果为;
[<Element html at 0x252717bfc48>, <Element body at 0x252717bfd48>, <Element div at 0x252717bfd88>, <Element ul at 0x252717bfdc8>, <Element li at
0x252717bfe08>, <Element a at 0x252717bfe88>, <Element li at 0x252717bfec8>, <Element a at 0x252717bff08>, <Element li at 0x252717bff48>, <Element a at
0x252717bfe48>, <Element li at 0x252717bff88>, <Element a at 0x252717bffc8>, <Element li at 0x252717ca048>, <Element a at 0x252717ca088>]
如果只想要匹配还有
- 的节点。
-
from xml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li') print(result) print(result[0])
输出结果为:
from lxml import etree html = etree.parse('./test.html', etree.HTMLParser()) result = html.xpath('//li') print(result) print(result[0])
子节点
我们通过/或则//即可查找元素的子节点或子孙结点,假如想选择li节点的所有直接a子节点,
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li/a') print(result)
输出结果为:
[<Element a at 0x14a4450fcc8>, <Element a at 0x14a4450fd08>, <Element a at 0x14a4450fd48>, <Element a at 0x14a4450fd88>, <Element a at 0x14a4450fdc8>]
此处的/用于选取直接子节点,如果要获取所有的子孙节点,就可以使用//。
from lxml import etree html = etree.parse('./test//html',etree.HTMLParser()) result = html.xpath('//url//a') print(result)
输出节点和上式得相同:
[<Element a at 0x18bc89cfc48>, <Element a at 0x18bc89cfc88>, <Element a at 0x18bc89cfcc8>, <Element a at 0x18bc89cfd08>, <Element a at 0x18bc89cfd48>]
父节点
前面是介绍子节点下面来介绍子节点。
比如我们首先选中herf属性为link4.html的a节点。from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//a[@href="link4.html"]/../@class') print(result)
输出结果为;
['item-1']
xpath如何匹配的:1.首先选中href属性为link4.html的a节点,然后再获取其父节点,然后再获取其class属性。
属性匹配:
在选项的时候我们还可以用@符号进行属性过滤,比如这里我们要选取class为item-0的li节点。
可以这样去实现:from lxml import etree html = etree.parse('./test.html',etree.HTMLParse()) result = html.xpath('//li[@class="item-0"]') print(result)
学到这里我不尽想停下来学习一下html语言,尽管大概明白其中的含义,但这种迷迷糊糊的感觉令人不自在我决定先跳过本章下面内容尽快完成html语言的基本语法。