爬虫学习第六天—数据提取
一、数据提取概述
1、响应数据内容分类
- 结构化响应内容:
- json 字符串
- 可以使用re、json等模块来提取特定数据。
- json字符串示例:

- xml 字符串
- 可以使用re、lxml等模块来提取特定数据
- xml字符串的示例如下:
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
- 非结构化的响应内容
- html字符串
- 可以使用re、lxml等模块来提取特定数据
- html字符串示例:

2、认识xml,以及xml和html的区别
2.1 认识xml
xml是一种可扩展标记语言,样子和html很像,功能更专注于对传输和存储数据
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
上面的xml内容可以表示为下面的树结构:

2.2 xml和html的区别
二者区别如图

html:
- 超文本标记语言
- 为了更好的显示数据,侧重点是为了显示
xml:
- 可扩展标记语言
- 为了传输和存储数据,侧重点是在于数据内容本身
2.3 常用数据解析方法

二、jsonpath模块
1、jsonpath使用场景
如果有一个多层嵌套的复杂字典,想要根据key和下标来批量提取value,这是比较困难的。jsonpath模块就能解决这个痛点,接下来我们就来学习jsonpath模块。
jsonpath可以按照key对python字典进行批量数据提取
2、jsonpath模块的安装
jsonpath是第三方模块,需要额外安装
pip install jsonpath
3、jsonpath模块提取数据方法
from jsonpath import jsonpath
ret = jsonpath(a, 'jsonpath语法规则字符串')
4、jsonpath语法规则
4.1、操作符
符号 | 描述 |
---|
$ | 查询的根节点对象,用于表示一个json数据,可以是数组或对象 |
@ | 过滤器(filter predicate)处理的当前节点对象 |
* | 获取所有节点 |
. or [] | 获取子节点 |
… | 递归搜索,筛选所有符合条件的节点 |
?() | 递归搜索,筛选所有符合条件的节点 |
[start:end] | 数组片段,区间为[start,end),不包含end |
[A]或[A,B] | 迭代器下标,表示一个或多个数组下标 |
() | 支持表达式计算 |
4.2、函数
可以在JsonPath表达式执行后进行调用,其输入值为表达式的结果。
名称 | 描述 |
---|
min() | 获取数值类型数组的最小值 |
max() | 获取数值类型数组的最大值 |
length() | 获取数值类型数组的长度,例如$.data.length() |
4.3、过滤器
操作符 | 描述 |
---|
== | 等于 |
!= | 不等于 |
< | 小于 |
in | 所属符号,例如[?(@.type in [“小雨”,“中到大雨”])] |
nin | 排除符号 |
=~ | 判断是否符合正则表达式,例如[?(@.type =~ /^小雨.*/)] |
5、示例
示例json文档如下:
book_dict = {
"store": {
"book": [
{ "press": "机械工业出版社",
"author": "刘天斯",
"title": "Python自动化运维",
"price": 39.99
},
{ "press": "机械工业出版社",
"author": "李松涛",
"title": "Ansible 权威指南",
"price": 39.88
},
{ "press": "清华大学出版社",
"author": "董付国",
"title": "Python程序设计开发宝典",
"isbn": "0-553-21311-3",
"price": 65.88
},
{ "press": "吉林大学出版社",
"author": "王国辉",
"title": "Python从入门到项目实践",
"isbn": "0-395-19395-8",
"price": 78.98
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
示例演示结果
from jsonpath import jsonpath
$..author # 显示所有的作者
print(jsonpath(book_dict, '$..author'))
结果:
['刘天斯', '李松涛', '董付国', '王国辉']
$.store.book[*].author # store中所有的book的作者
print(jsonpath(book_dict, '$.store.book[*].author'))
结果:
['刘天斯', '李松涛', '董付国', '王国辉']
$.store.* # store 下所有的元素
print(jsonpath(book_dict,'$.store.*'))
结果:
[[{'press': '机械工业出版社', 'author': '刘天斯', 'title': 'Python自动化运维', 'price': 39.99}, {'press': '机械工业出版社', 'author': '李松涛', 'title': 'Ansible 权威指南', 'price': 39.88}, {'press': '清华大学出版社', 'author': '董付国', 'title': 'Python程序设计开发宝典', 'isbn': '0-553-21311-3', 'price': 65.88}, {'press': '吉林大学出版社', 'author': '王国辉', 'title': 'Python从入门到项目实践', 'isbn': '0-395-19395-8', 'price': 78.98}], {'color': 'red', 'price': 19.95}]
$.store..price # store下所有的价格
print(jsonpath(book_dict,'$.store..price'))
结果:
[39.99, 39.88, 65.88, 78.98, 19.95]
$..book[2] # 获取第二本书的信息
print(jsonpath(book_dict,'$..book[2]'))
结果:
[{'press': '清华大学出版社', 'author': '董付国', 'title': 'Python程序设计开发宝典', 'isbn': '0-553-21311-3', 'price': 65.88}]
$..book[(@.length-1)] or $..book[-1:] # 获取最后一本书的信息
print(jsonpath(book_dict,'$..book[(@.length-1)]'))
print(jsonpath(book_dict,'$..book[-1:]'))
结果:
[{'press': '吉林大学出版社', 'author': '王国辉', 'title': 'Python从入门到项目实践', 'isbn': '0-395-19395-8', 'price': 78.98}]
$..book[0,1] or $..book[:2] # 获取前两本书的内容
print(jsonpath(book_dict,'$..book[0,1]'))
print(jsonpath(book_dict,'$..book[:2]'))
结果:
[{'press': '机械工业出版社', 'author': '刘天斯', 'title': 'Python自动化运维', 'price': 39.99}, {'press': '机械工业出版社', 'author': '李松涛', 'title': 'Ansible 权威指南', 'price': 39.88}]
$..book[?(@.isbn)] # 获取有isbn的所有数据
print(jsonpath(book_dict,'$..book[?(@.isbn)]'))
结果:
[{'press': '清华大学出版社', 'author': '董付国', 'title': 'Python程序设计开发宝典', 'isbn': '0-553-21311-3', 'price': 65.88}, {'press': '吉林大学出版社', 'author': '王国辉', 'title': 'Python从入门到项目实践', 'isbn': '0-395-19395-8', 'price': 78.98}]
$..book[?(@.price>50)] # 价格大于50的所有数据
print(jsonpath(book_dict,'$..book[?(@.price>50)]'))
结果:
[{'press': '清华大学出版社', 'author': '董付国', 'title': 'Python程序设计开发宝典', 'isbn': '0-553-21311-3', 'price': 65.88}, {'press': '吉林大学出版社', 'author': '王国辉', 'title': 'Python从入门到项目实践', 'isbn': '0-395-19395-8', 'price': 78.98}]
6、拉钩的jsonpath示例
import requests
import json
import jsonpath
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0'
}
url = 'https://www.lagou.com/lbs/getAllCitySearchLabels.json'
reponse = requests.get(url,headers=headers)
dict_data = json.loads(reponse.content)
city = jsonpath.jsonpath(dict_data,'$..A..name')
print(city)