文章目录

  • 使用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的使用相关推荐

  1. python网络爬虫学习笔记(6)动态网页抓取(一)知识

    文章目录 网络爬虫学习笔记(2) 1 资料 2 笔记 2-1 动态抓取概述 2-2 通过浏览器审查元素解析真实网页地址 2-3 网页URL地址的规律 2-4 json库 2-5 通过Selenium模 ...

  2. python网络爬虫学习笔记(7)动态网页抓取(二)实践

    文章目录 1 资料 2 笔记 2-1 准备 2-1-1. 网址 2-2-2 文本位置 2-2 代码 2-2-1 原型 2-2-2 ver0.1 1 资料 <Python网络爬虫从入门到实践> ...

  3. python 网络爬虫学习笔记(一)

    为了方便,在Windows下我用了PyCharm,个人感觉这是一款优秀的python学习软件.爬虫,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去 ...

  4. Python网络爬虫学习笔记(二)基本库的使用

    基本库的使用 最基础的 HTTP 库有 urllib . httplib2 . requests . treq 等 . 使用urlib urlib 包含四个模块 口 request : 它是最基本的 ...

  5. python网络爬虫学习笔记(二):爬虫基本概述

    1.爬虫的基本概述 (1) 获取网页 爬虫首先要做的工作就是获取网页,这里就是获取网页的源代码.源代码里包含了网页的部分有用信息,所以只要把源代码获取下来,就可以从中提取想要的信息了. python提 ...

  6. python网络爬虫学习笔记(三):urllib库的使用

    文章目录 使用urllib库 1.urllib.request.urlopen()函数 urlopen()函数API: 2.urllib.request函数 验证 Cookies 保存Cookies ...

  7. python网络爬虫学习笔记(一):网页基础

    1.URI和URL URI的全称为Uniform Resource Identifier,即统一资源标志符,URL的全称为Universal Resource Locator,即统一资源定位符. 2. ...

  8. python网络爬虫学习笔记(十一):Ajax数据爬取

    文章目录 1.基本介绍 2.基本原理 3.实战 有时候我们在用requests抓取页面的时候,得到的结果可能和在浏览器中看到的不一样:在浏览器中可以看到正常显示的页面数据,但是使用requests得到 ...

  9. python网络爬虫学习笔记(十):数据存储

    文章目录 1.文本存储 2.JSON文件存储 2.1 读取JOSN 2.2 输出JSON 3.CSV文件存储 3.1 写入 3.2 读取 1.文本存储 import requests from pyq ...

最新文章

  1. List元素互换,List元素转换下标,Java Collections.swap()方法实例解析
  2. 2017上半年软考 第七章 重要知识点
  3. GNU make manual 翻译( 一百一十三)
  4. Exchange2010配置实验(六)部署forefront到edge服务器
  5. 什么是云服务举例说明_云服务是什么功能
  6. 【NLP】AAAI21最佳论文Runners Up!Transformer的归因探索!
  7. vhdl变量赋初值_5.5 C++自动变量
  8. matlab子函数调用变量,matlab中,怎么样用function自定义函数调用另一个函数名为输入?...
  9. CSS中背景颜色、背景图片、渐变色、背景定位、精灵图(雪碧图)介绍
  10. Intellij IDEA社区版集成Maven插件
  11. Web Hacking 101 中文版 五、HTML 注入
  12. php区分全角半角字符,php如何判断是字符串全角还是半角
  13. XWiki 4.4.1 发布,Java 的 Wiki 引擎
  14. 电路计算机辅助设计上海电力学院,上海电力学院电路计算机辅助设计1.doc
  15. 远程桌面连接(连接服务器)报错Oracle修正
  16. Nginx+tomcat整合
  17. FME 坐标系使用(二)----关于Beijing54坐标系和Xian80坐标系说明的补充
  18. 源码下载地址及各类资源站点
  19. abc242 D(脑子一团浆糊)
  20. TFHE同态库的Torus32

热门文章

  1. LINUX 文件夹打包
  2. 2017计算机基础教学大纲,2017级大学计算机基础教学大纲
  3. Ubuntu 18 LTS netplan 网络配置
  4. spring boot(三)Junit 测试controller
  5. node 无脑生成小程序二维码图
  6. PyQt4 的事件与信号 -- 发射信号
  7. TeXmacs - 所见即所得 - 专业排版软件
  8. url、href、src 详解
  9. 二叉树与树、森林之间的转换
  10. 用命令行发邮件——让你更加了解smtp