Python爬虫之xpath语法及案例使用

---- 钢铁侠的知识库 2022.08.15

我们在写Python爬虫时,经常需要对网页提取信息,如果用传统正则表达去写会增加很多工作量,此时需要一种对数据解析的方法,也就是本章要介绍的Xpath表达式。

Xpath是什么

XPath,全称 XML Path Language,即 XML 路径语言,它是一门在 XML 文档中查找信息的语言。最初是用来搜寻 XML 文档的,但同样适用于 HTML 文档的搜索。所以在做爬虫时完全可以使用 XPath 做相应的信息抽取。

XPath 的选择功能十分强大,它提供了非常简洁明了的路径选择表达式。另外,它还提供超过 100 个内置函数,用于字符串、数值、时间的匹配以及节点、序列的处理等,几乎所有想要定位的节点都可以用 XPath 来选取。

下面介绍实战中常用的几个知识点,详细也可以看W3C介绍:https://www.w3school.com.cn/xpath/index.asp

Xpath语法介绍

路径常用规则

表达式 描述 实例
nodename 选取此节点的所有子节点 xpath('//div') 选取了div节点的所有子节点
/ 从根节点选取 xpath('/div') 从根节点上选取div节点
// 选取所有当前节点,不考虑位置 xpath('//div') 选取所有的div节点
. 选取当前节点 xpath('./div') 选取当前节点下的div节点
.. 选取当前节点的父节点 xpath('..') 回到上一个节点
@ 选取属性 xpath('//@calss') 选取所有的class属性

谓语规则

谓语被嵌在方括号内,用来查找某个特定的节点或包含某个制定的值的节点

表达式 结果
xpath('/body/div[1]') 选取body下的第一个div节点
xpath('/body/div[last()]') 选取body下最后一个div节点
xpath('/body/div[last()-1]') 选取body下倒数第二个div节点
xpath('/body/div[positon()️]') 选取body下前两个div节点
xpath('/body/div[@class]') 选取body下带有class属性的div节点
xpath('/body/div[@class="main"]') 选取body下class属性为main的div节点
xpath('/body/div[price>35.00]') 选取body下price元素值大于35的div节点

通配符

通配符来选取未知的XML元素

表达式 结果
xpath('/div/*') 选取div下的所有子节点
xpath('/div[@*]') 选取所有带属性的div节点

取多个路径

使用“|”运算符可以选取多个路径

表达式 结果
xpath('//div|//table') 选取所有的div和table节点

功能函数

使用功能函数能够更好的进行模糊搜索

函数 用法 解释
starts-with xpath('//div[starts-with(@id,"ma")]') 选取id值以ma开头的div节点
contains xpath('//div[contains(@id,"ma")]') 选取id值包含ma的div节点
and xpath('//div[contains(@id,"ma") and contains(@id,"in")]') 选取id值包含ma和in的div节点
text() xpath('//div[contains(text(),"ma")]') 选取节点文本包含ma的div节点

语法熟悉

下面举一段HTML文本进行语法热身,代码如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# time: 2022/8/8 0:05
# author: gangtie
# email: 648403020@qq.com
from lxml import etree text = '''
<div>
<ul id='ultest'>
<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"><span>fourth item</span></a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
'''
# 调用HTML类进行初始化,这样就成功构造了一个XPath解析对象。
# 利用etree.HTML解析字符串
page = etree.HTML(text)
print(type(page))

可以看到打印结果已经变成XML元素:

<class 'lxml.etree._Element'>

字符串转换HTML

字符串利用etree.HTML解析成html格式:

print(etree.tostring(page,encoding='utf-8').decode('utf-8'))

```
<html><body><div>
<ul id="ultest">
<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"><span>fourth item</span></a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</li></ul>
</div>
</body></html> Process finished with exit code 0
```

经过处理可以看到缺失的</li>也自动补全了,还自动添加html、body节点。

查找绝对路径

通过绝对路径获取a标签的所有内容

a = page.xpath("/html/body/div/ul/li/a")
for i in a:
print(i.text) ```
first item
second item
third item
None
fifth item
```

查找相对路径(常用)

查找所有li标签下的a标签内容

html = etree.HTML(text)
a = html.xpath("//a/text()")
print(a) ```
['first item', 'second item', 'third item', 'fifth item']
```

当前标签节点

. 表示选取当前标签的节点。

我们先定位 ul 元素节点得到一个列表,打印当前节点列表得到第一个 ul,

接着打印 ul 节点的子节点 li,text()输出。

page = etree.HTML(text)
ul = page.xpath("//ul")
print(ul)
print(ul[0].xpath("."))
print(ul[0].xpath("./li"))
print(ul[0].xpath("./li/a/text()")) ```
[<Element ul at 0x234d16186c0>]
[<Element ul at 0x234d16186c0>]
[<Element li at 0x234d1618ac0>, <Element li at 0x234d1618b00>, <Element li at 0x234d1618b40>, <Element li at 0x234d1618b80>, <Element li at 0x234d1618bc0>]
['first item', 'second item', 'third item', 'fifth item']
```

父节点

.. 表示选取当前标签的父节点。

可以看到得到ul的上一级div

page = etree.HTML(text)
ul = page.xpath("//ul")
print(ul[0].xpath("."))
print(ul[0].xpath("..")) ```
[<Element ul at 0x1d6d5cd8540>]
[<Element div at 0x1d6d5cd8940>]
```

属性匹配

匹配时可以用@符号进行属性过滤

查找a标签下属性href值为link2.html的内容

html = etree.HTML(text)
a = html.xpath("//a[@href='link2.html']/text()")
print(a) ```
['second item']
```

函数

last():查找最后一个li标签里的a标签的href属性

html = etree.HTML(text)
a = html.xpath("//li[last()]/a/text()")
print(a) ```
['fifth item']
```

contains:查找a标签中属性href包含link的节点,并文本输出

html = etree.HTML(text)
a = html.xpath("//a[contains(@href, 'link')]/text()")
print(a) ```
['first item', 'second item', 'third item', 'fifth item']
```

实战案例

上面说完基本用法,接下来做几个实战案例练练手。

案例一:豆瓣读书

#  -*-coding:utf8 -*-
# 1.请求并提取需要的字段
# 2.保存需要的数据
import requests
from lxml import etree class DoubanBook(): def __init__(self):
self.base_url = 'https://book.douban.com/chart?subcat=all&icn=index-topchart-popular'
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/104.0.0.0 Safari/537.36'
} # 请求并提取需要的字段
def crawl(self):
res = requests.get(self.base_url, headers=self.headers)
lis = etree.HTML(res.text).xpath('//*[@id="content"]/div/div[1]/ul/li')
# print(type(lis))
books = []
for li in lis:
# print(etree.tostring(li,encoding='utf-8').decode('utf-8'))
# print("==================================================")
title = "".join(li.xpath(".//a[@class='fleft']/text()"))
score = "".join(li.xpath(".//p[@class='clearfix w250']/span[2]/text()"))
# list输出带有['\n 刘瑜 / 2022-4 / 广西师范大学出版社 / 82.00元 / 精装\n ']
publishing = "".join(li.xpath(".//p[@class='subject-abstract color-gray']/text()")).strip()
book = {
'title': title,
'score': score,
'publishing': publishing,
}
books.append(book)
self.save_data(books) def save_data(self, datas):
with open('books.txt', 'w', encoding='utf-8') as f:
f.write(str(datas)) def run(self):
self.crawl() if __name__ == '__main__':
DoubanBook().run()

案例二:彼岸图片下载

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author: 钢铁知识库
# email: 648403020@qq.com import os
import requests
from lxml import etree # 彼岸图片下载
class BiAn(): def __init__(self):
self.url = 'https://pic.netbian.com'
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/104.0.0.0 Safari/537.36',
'cookie': '__yjs_duid=1_cb922eedbda97280755010e53b2caca41659183144320; Hm_lvt_c59f2e992a863c2744e1ba985abaea6c=1649863747,1660203266; zkhanecookieclassrecord=%2C23%2C54%2C55%2C66%2C60%2C; Hm_lpvt_c59f2e992a863c2744e1ba985abaea6c=1660207771; yjs_js_security_passport=1225f36e8501b4d95592e5e7d5202f4081149e51_1630209607_js'
}
# 如果目录不存在会报错
if not os.path.exists('BianPicture'):
os.mkdir('BianPicture') # 请求拿到ul列表
def crawl(self):
res = requests.get(self.url, headers=self.headers)
res.encoding = 'gbk'
uls = etree.HTML(res.text).xpath('//div[@class="slist"]/ul[@class="clearfix"]/li')
# print(etree.tostring(uls,encoding='gbk').decode('gbk')) # 循环拿到图片名、图片地址,拼接请求再次下载到图片
for ul in uls:
img_name = ul.xpath('.//a/b/text()')[0]
img_src = ul.xpath('.//a/span/img/@src')[0]
# print(img_name + img_src)
img_url = self.url + img_src
# 拼接后下载图片,转义Bytes
img_res = requests.get(img_url, headers=self.headers).content
img_path = "BianPicture/" + img_name + ".jpg"
data = {
'img_res': img_res,
'img_path': img_path
}
self.save_data(data) # 数据保存逻辑
def save_data(self, data):
with open(data['img_path'], 'wb') as f:
f.write(data['img_res'])
# print(data) def run(self):
self.crawl() if __name__ == '__main__':
BiAn().run()

案例三:全国城市名称爬取

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author: 钢铁知识库
# email: 648403020@qq.com
import os import requests
from lxml import etree class CityName():
def __init__(self):
self.url = 'https://www.aqistudy.cn/historydata/'
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}
# 判断目录是否存在
if not os.path.exists('city_project'):
os.mkdir('city_project') def crawl(self):
res = requests.get(url=self.url, headers=self.headers).text
uls = etree.HTML(res).xpath('//div[@class="all"]/div[2]/ul/div[2]/li') all_city_name = list()
for ul in uls:
city_name = ul.xpath('.//a/text()')[0]
# print(type(city_name))
all_city_name.append(city_name)
self.save_data(all_city_name) def save_data(self, data):
with open('./city_project/city.txt', 'w') as f:
f.write(str(data)) def run(self):
self.crawl() if __name__ == '__main__':
CityName().run()

xpath使用工具

chrome生成XPath表达式

经常使用chome的朋友都应该知道这功能,在 审查 状态下(快捷键ctrl+shift+i,F12),定位到元素(快捷键ctrl+shift+c) ,在Elements选项卡中,右键元素 Copy->Copy xpath,就能得到该元素的xpath了

Xpath Helper插件

为chome装上XPath Helper就可以很轻松的检验自己的xpath是否正确了。安装插件需要特别上网,安装好插件后,在chrome右上角点插件的图标,调出插件的黑色界面,编辑好xpath表达式,表达式选中的元素被标记为黄色

---- 钢铁侠的知识库 2022.08.15

结语:

以上就是利用XPath的所有用法,从常用语法,到案例练习都走了一遍。下一章 钢铁知识库 会继续介绍另一种好用的解析框架,Beautiful Soup,觉得有用点赞加关注,就当你送了红包666

Python爬虫之xpath语法及案例使用的更多相关文章

  1. python爬虫:XPath语法和使用示例

    python爬虫:XPath语法和使用示例 XPath(XML Path Language)是一门在XML文档中查找信息的语言,可以用来在XML文档中对元素和属性进行遍历. 选取节点 XPath使用路 ...

  2. Python爬虫基础——XPath语法的学习与lxml模块的使用

    XPath与正则都是用于数据的提取,二者的区别是: 正则:功能相对强大,写起来相对复杂: XPath:语法简单,可以满足绝大部分的需求: 所以,如果你可以根据自己的需要进行选择. 一.首先,我们需要为 ...

  3. Python爬虫:Xpath语法笔记

    一.选取节点 常用的路劲表达式: 表达式 描述 实例   nodename 选取nodename节点的所有子节点 xpath(‘//div’) 选取了div节点的所有子节点 / 从根节点选取 xpat ...

  4. 非常全的一份Python爬虫的Xpath博文

    非常全的一份Python爬虫的Xpath博文 Xpath 是 python 爬虫过程中非常重要的一个用来定位的一种语法. 一.开始使用 首先我们需要得到一个 HTML 源代码,用来模拟爬取网页中的源代 ...

  5. 【python爬虫】Xpath

    一.xml是什么 1.定义:可扩展标记性语言 2.特点:xml的是具有自描述结构的半结构化数据. 3.作用:xml主要设计宗旨是用来传输数据的.他还可以作为配置文件. 二.xml和html的区别 1. ...

  6. python爬虫中XPath和lxml解析库

    什么是XML XML 指可扩展标记语言(EXtensible Markup Language) XML 是一种标记语言,很类似 HTML XML 的设计宗旨是传输数据,而非显示数据 XML 的标签需要 ...

  7. 【Day3】4.Xpath语法与案例

    课程目标 1.谷歌浏览器配置Xpath 2.Xpath常用语法 3.Xpath常用案例 1.谷歌浏览器配置Xpath Xpath下载:http://chromecj.com/web-developme ...

  8. python爬虫之xpath的基本使用

    一.简介 Xpath是一门在XML文档中查找信息的语言.Xpath可用来在XML文档中对元素和属性进行遍历.Xpath是W3C XSLT标准的主要元素,并且XQuery和XPointer都构建于XPa ...

  9. Python爬虫Scrapy(二)_入门案例

    本章将从案例开始介绍python scrapy框架,更多内容请参考:python学习指南 入门案例 学习目标 创建一个Scrapy项目 定义提取的结构化数据(Item) 编写爬取网站的Spider并提 ...

随机推荐

  1. MVC 调试页面路径变成 Views/Controller/Action.cshtml问题

    MVC在路由里面已经写好了路径,但是调试时地址栏还是会变成 Views/Controller/Action.cshtml,导致报404错误,找不到路径. 原因可能是你将某一页面设为了起始页,导致每次运 ...

  2. IDEA windows版本快捷键

    使用本快捷键前,可以在idea使用下面方法确认版本! Ctrl 快捷键 介绍 Ctrl + F 在当前文件进行文本查找 (必备)Ctrl + R 在当前文件进行文本替换 (必备) Ctrl + Z 撤 ...

  3. Win10 LTSC 2021 安装及相关bug解决

    Win10 LTSC 2021 安装及相关bug解决 目录 Win10 LTSC 2021 安装及相关bug解决 准备文件 系统安装 系统激活 修复CPU占用高和输入法显示bug 安装微软应用商店 推 ...

  4. Spring AOP快速使用教程

    ​ Spring是方法级别的AOP框架,我们主要也是以某个类的某个方法作为连接点,用动态代理的理论来说,就是要拦截哪个方法织入对应的AOP通知.为了更方便的测试我们首先创建一个接口 public in ...

  5. linux运维基础2

    内容概要 虚拟机关键配置名词解释 远程链接工具 xshell基本使用 linux命令准则 系统运⾏命令 常用快捷方式 文件命令操作 文件编辑命令 内容详情 虚拟机关键配置名词解释 # 虚拟网络编辑器说 ...

  6. 渗透测试之sql注入验证安全与攻击性能

    由于渗透测试牵涉到安全性以及攻击性,为了便于交流分享,本人这里不进行具体网址的透露了. 我们可以在网上查找一些公司官方网站如(http://www.XXXXXX.com/xxxx?id=1) 1.拿到 ...

  7. CAP:多重注意力机制,有趣的细粒度分类方案 | AAAI 2021

    论文提出细粒度分类解决方案CAP,通过上下文感知的注意力机制来帮助模型发现细微的特征变化.除了像素级别的注意力机制,还有区域级别的注意力机制以及局部特征编码方法,与以往的视觉方案很不同,值得一看 来源 ...

  8. 论文阅读 Exploring Temporal Information for Dynamic Network Embedding

    10 Exploring Temporal Information for Dynamic Network Embedding 5 link:https://scholar.google.com.sg ...

  9. 在linux上配置Maven环境变量

    1.首先下载maven ,这里我使用的是3.8.1 Maven – Download Apache Maven 2.在linux环境中,将maven上传至 /usr/local/目录中 这里我将mav ...

  10. 蒸腾量与蒸散量(ET)数据、潜在蒸散量、实际蒸散量数据、气温数据、降雨量数据

    ​   数据下载链接:数据下载链接 引言 多种卫星遥感数据反演地表蒸腾与蒸散率(ET)产品是地理遥感生态网推出的生态环境类数据产品之一,产品包括2000-2009年三个波段RGB数据,值域0-252之 ...