python网络爬虫学习笔记(八):XPath的使用
文章目录
- 使用XPath
- 1.XPath常用规则
- 2.所有节点
- 3.子节点
- 4.父节点
- 5.属性匹配
- 6.文本获取
- 7.属性获取
- 8.按序选择
使用XPath
XPath,全称XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言。
1.XPath常用规则
这里列出了XPath的常用匹配规则,示例如下:
//title[@lang='eng']
这就是一个XPath规则,它代表选择所有名称为title,同时属性lang的值为eng的节点。
后面会通过Python的lxml库,利用XPath进行HTML的解析。
我们来看一个实例:
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文本,调用HTML类进行初始化,这样就成功构造了一个XPath解析对象。HTML文本中的最后一个li节点是没有闭合的,但是etree模块可以自动修正HTML文本。
这里我们调用tostring()方法即可输出修正后的HTML代码,但是结果是bytes类型。这里利用decode()方法将其转成str类型,结果如下:
<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>
可以看到,经过处理之后,li节点标签被补全,并且还自动添加了body、html节点。
另外,也可以直接读取文本文件进行解析,示例如下:
from lxml import etreehtml = 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>
这次的输出结果略有不同,多了一个DOCTYPE的声明,不过对解析无任何影响
2.所有节点
我们一般会用//开头的XPath规则来选取所有符合要求的节点。这里以前面的HTML文本为例,如果要选取所有节点,可以这样实现:
from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//*')
print(result)
[<Element html at 0x1f6c0205648>, <Element body at 0x1f6c0019bc8>, <Element div at 0x1f6c0019c88>, <Element ul at 0x1f6c0205348>, <Element li at 0x1f6c0205688>, <Element a at 0x1f6c0205708>, <Element li at 0x1f6c0205748>, <Element a at 0x1f6c0205788>, <Element li at 0x1f6c02057c8>, <Element a at 0x1f6c02056c8>, <Element li at 0x1f6c0205808>, <Element a at 0x1f6c0205848>, <Element li at 0x1f6c0205888>, <Element a at 0x1f6c02058c8>]
这里使用*代表匹配所有节点,也就是整个HTML文本中的所有节点都会被获取。可以看到,返回形式是一个列表,每个元素是Element类型,其后跟了节点的名称,如html、body、div、ul、li、a等,所有节点都包含在列表中了。
当然,此处匹配也可以指定节点名称。如果想获取所有li
节点,示例如下:
from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li')
print(result)
print(result[0])
[<Element li at 0x1f6c01e6f88>, <Element li at 0x1f6c0205cc8>, <Element li at 0x1f6c0205d08>, <Element li at 0x1f6c0205d48>, <Element li at 0x1f6c0205d88>]
<Element li at 0x1f6c01e6f88>
这里可以看到提取结果是一个列表形式,其中每个元素都是一个 Element对象。如果要取出其中一个对象,可以直接用中括号加索引,如[0]。
3.子节点
我们通过/或//即可查找元素的子节点或子孙节点。假如现在想选择li节点的所有直接a子节点,可以这样实现:
from lxml import etreehtml = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a')
print(result)
[<Element a at 0x1f6c01e6fc8>, <Element a at 0x1f6c0205588>, <Element a at 0x1f6c0205e08>, <Element a at 0x1f6c0205e48>, <Element a at 0x1f6c0205e88>]
/
用于选取直接子节点,如果要获取所有子孙节点,就可以使用//
。例如,要获取ul
节点下的所有子孙a
节点,可以这样实现:
from lxml import etreehtml = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//ul//a')
print(result)
[<Element a at 0x1f6c02058c8>, <Element a at 0x1f6c0205908>, <Element a at 0x1f6c02070c8>, <Element a at 0x1f6c0207108>, <Element a at 0x1f6c0207148>]
但是如果这里用//ul/a
,就无法获取任何结果了。因为/
用于获取直接子节点,而在ul
节点下没有直接的a
子节点,只有li
节点,所以无法获取任何匹配结果,代码如下:
from lxml import etreehtml = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//ul/a')
print(result)
[]
4.父节点
用..
来实现
from lxml import etree
html = etree.parse('test.html', etree.HTMLParser())
result = html.xpath('//a[@href = "link4.html"]/../@class')
print(result)
['item-1']
我们也可以通过parent::来获取父节点:
from lxml import etree
html = etree.parse('test.html', etree.HTMLParser())
result = html.xpath('//a[@href = "link4.html"]/parent::*/@class')
print(result)
['item-1']
5.属性匹配
@
符号用于进行属性过滤,如选取class为item-1的li节点:
from lxml import etreehtml = etree.parse('test.html', etree.HTMLParser())result = html.xpath('//li[@class = "item-0"]')
print(result)
[<Element li at 0x1f6c038cd08>, <Element li at 0x1f6c038c788>]
6.文本获取
我们用XPath中的text()方法获取li节点中的文本:
from lxml import etreehtml = etree.parse('test.html', etree.HTMLParser())result = html.xpath('//li[@class = "item-0"]/a/text()')
print(result)
['first item', 'fifth item']
我们再来看看使用//
选取的结果:
from lxml import etreehtml = etree.parse('test.html', etree.HTMLParser())result = html.xpath('//li[@class = "item-0"]//text()')
print(result)
['first item', 'fifth item', '\r\n ']
里是选取所有子孙节点的文本,其中前两个就是li的子节点a节点内部的文本,另外一个就是最后一个li节点内部的文本,即换行符。
7.属性获取
使用@
符号获取属性
from lxml import etreehtml = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a/@href')
print(result)
['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']
某些节点的某个属性可能有多个值,这里HTML文本中li节点的class属性有两个值li和li-first,此时如果还想用之前的属性匹配获取,就无法匹配了:
from lxml import etree
text = '''
<li class="li li-first"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[@class="li"]/a/text()')
print(result)
[]
我们可以使用contains()
函数来获取:
from lxml import etree
text = '''
<li class="li li-first"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[contains(@class, "li")]/a/text()')
print(result)
['first item']
如果一个节点都多个属性,可以使用and
来连接
from lxml import etree
text = '''
<li class="li li-first" name="item"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
print(result)
['first item']
另外,还有很多运算符,如or、mod等:
8.按序选择
我们选取了第一个li节点,中括号中传入数字1,选取最后一个li节点,中括号中传入last(),选取倒数第三个li节点,中括号中传入last() - 2
from lxml import etreetext = '''
<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 = html.xpath('//li[1]/a/text()')
print(result)
result = html.xpath('//li[last()]/a/text()')
print(result)
result = html.xpath('//li[position()<3]/a/text()')
print(result)
result = html.xpath('//li[last()-2]/a/text()')
print(result)
['first item']
['fifth item']
['first item', 'second item']
['third item']
python网络爬虫学习笔记(八):XPath的使用相关推荐
- python网络爬虫学习笔记(6)动态网页抓取(一)知识
文章目录 网络爬虫学习笔记(2) 1 资料 2 笔记 2-1 动态抓取概述 2-2 通过浏览器审查元素解析真实网页地址 2-3 网页URL地址的规律 2-4 json库 2-5 通过Selenium模 ...
- python网络爬虫学习笔记(7)动态网页抓取(二)实践
文章目录 1 资料 2 笔记 2-1 准备 2-1-1. 网址 2-2-2 文本位置 2-2 代码 2-2-1 原型 2-2-2 ver0.1 1 资料 <Python网络爬虫从入门到实践> ...
- python 网络爬虫学习笔记(一)
为了方便,在Windows下我用了PyCharm,个人感觉这是一款优秀的python学习软件.爬虫,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去 ...
- Python网络爬虫学习笔记(二)基本库的使用
基本库的使用 最基础的 HTTP 库有 urllib . httplib2 . requests . treq 等 . 使用urlib urlib 包含四个模块 口 request : 它是最基本的 ...
- python网络爬虫学习笔记(二):爬虫基本概述
1.爬虫的基本概述 (1) 获取网页 爬虫首先要做的工作就是获取网页,这里就是获取网页的源代码.源代码里包含了网页的部分有用信息,所以只要把源代码获取下来,就可以从中提取想要的信息了. python提 ...
- python网络爬虫学习笔记(三):urllib库的使用
文章目录 使用urllib库 1.urllib.request.urlopen()函数 urlopen()函数API: 2.urllib.request函数 验证 Cookies 保存Cookies ...
- python网络爬虫学习笔记(一):网页基础
1.URI和URL URI的全称为Uniform Resource Identifier,即统一资源标志符,URL的全称为Universal Resource Locator,即统一资源定位符. 2. ...
- python网络爬虫学习笔记(十一):Ajax数据爬取
文章目录 1.基本介绍 2.基本原理 3.实战 有时候我们在用requests抓取页面的时候,得到的结果可能和在浏览器中看到的不一样:在浏览器中可以看到正常显示的页面数据,但是使用requests得到 ...
- python网络爬虫学习笔记(十):数据存储
文章目录 1.文本存储 2.JSON文件存储 2.1 读取JOSN 2.2 输出JSON 3.CSV文件存储 3.1 写入 3.2 读取 1.文本存储 import requests from pyq ...
最新文章
- List元素互换,List元素转换下标,Java Collections.swap()方法实例解析
- 2017上半年软考 第七章 重要知识点
- GNU make manual 翻译( 一百一十三)
- Exchange2010配置实验(六)部署forefront到edge服务器
- 什么是云服务举例说明_云服务是什么功能
- 【NLP】AAAI21最佳论文Runners Up!Transformer的归因探索!
- vhdl变量赋初值_5.5 C++自动变量
- matlab子函数调用变量,matlab中,怎么样用function自定义函数调用另一个函数名为输入?...
- CSS中背景颜色、背景图片、渐变色、背景定位、精灵图(雪碧图)介绍
- Intellij IDEA社区版集成Maven插件
- Web Hacking 101 中文版 五、HTML 注入
- php区分全角半角字符,php如何判断是字符串全角还是半角
- XWiki 4.4.1 发布,Java 的 Wiki 引擎
- 电路计算机辅助设计上海电力学院,上海电力学院电路计算机辅助设计1.doc
- 远程桌面连接(连接服务器)报错Oracle修正
- Nginx+tomcat整合
- FME 坐标系使用(二)----关于Beijing54坐标系和Xian80坐标系说明的补充
- 源码下载地址及各类资源站点
- abc242 D(脑子一团浆糊)
- TFHE同态库的Torus32