爬虫 - JSONPath

JSONPath

JSONPath 简介

  • JSONPath:是 xpath 在 json 的应用,是用来解析 json 数据使用的
  • XML 的一个经常强调的优点是可以使用大量工具来分析、转换和有选择地从 XML 文档中提取数据。XPath 是这些功能强大的工具之一。它可以解决以下问题:
    1. 可以在客户端上以交互方式找到数据并从 JSON 结构中提取数据,而无需使用特殊脚本。
    2. 可以将客户端请求的 JSON 数据简化为服务器上的相关部分,从而最大程度地减少服务器响应的带宽使用量。

Python 处理 json 格式用到的函数

1
2
3
4
5
import json      导包
json.dumps(): 将字典或者列表转化为json格式的字符串
json.loads(): 将json格式字符串转化为python对象
json.dump(): 将字典或者列表转化为json格式字符串并且写入到文件中
json.load(): 从文件中读取json格式字符串,转化为python对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import json

lt = [
{'name': '王宝强', 'age': 30},
{'name': '贾乃亮', 'age': 36},
{'name': '马蓉蓉', 'age': 33},
{'name': '宋吉吉', 'age': 40},
{'name': '李小璐', 'age': 43},
]

# 将字典或者列表转化为json格式的字符串
string = json.dumps(lt, ensure_ascii=False)
print(string)

# 将json格式字符串转化为python对象
obj = json.loads(string)
print(obj)

# 将字典或者列表转化为json格式字符串并且写入到文件中
json.dump(lt, open('json.txt', 'w', encoding='utf8'), ensure_ascii=False)

# 从文件中读取json格式字符串,转化为python对象
obj = json.load(open('json.txt', 'r', encoding='utf8'))
print(obj)
print(type(obj))

前端处理

1
2
3
# 将json格式字符串转化为js对象
JSON.parse('json格式字符串')
eval('(' + json格式字符串 + ')')

安装

1
2
pip install lxml
pip install jsonpath

参考链接

jsonpath 和 xpath 的对比

XPath JSONPath Description
/ $ 表示根对象 / 元素
. @ 当前对象 / 元素
/ . or [] 子元素
.. n/a 父元素
// .. 任意位置查找
* * 通配符,表示所有的对象 / 元素
@ n/a 属性访问字符
[] [] 子元素操作符
| [,] 连接操作符在 XPath 结果合并其它结点集合。JSONP 允许 name 或者数组索引。
[] ?() 应用过滤器(脚本)表达式。
n/a () 脚本表达式,使用在脚本引擎下面。
() n/a Xpath 分组

XPath 提供的功能(此处没有缩写的语法,运算符和函数的位置路径)比此处列出的要多得多。此外,下标运算符在 Xpath 和 JSONPath 中的工作方式存在显着差异。

  • XPath 索引始终以 1 开始。
  • JSONPath 索引始终以 0 开头。

示例 1:测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import json
import jsonpath

# 将json格式字符串转化为Python对象
obj = json.load(open('book.json', 'r', encoding='utf8'))
# print(obj)

# 查找book下面所有的author
# book[0] 代表查询第一本书的作者
ret = jsonpath.jsonpath(obj, '$.store.book[*].author')
print(ret)

# 查找所有author
ret = jsonpath.jsonpath(obj, '$..author')
print(ret)

# 查找store下面所有的节点
ret = jsonpath.jsonpath(obj, '$.store.*')
print(ret)

# 查找store下面所有的price
ret = jsonpath.jsonpath(obj, '$.store..price')
print(ret)

# 查找第三个book,返回的是一个列表
ret = jsonpath.jsonpath(obj, '$..book[2]')
print(ret)

# 查找最后一本book
ret = jsonpath.jsonpath(obj, '$..book[(@.length-1)]')
print(ret)

# 前两本书
# ret = jsonpath.jsonpath(obj, '$..book[0,1]')
ret = jsonpath.jsonpath(obj, '$..book')[:2]
print(ret)

# 查找有isbn这个键的所有book
ret = jsonpath.jsonpath(obj, '$..book[?(@.isbn)]')
print(ret)

# 查找所有price键对应的值小于10的所有book
ret = jsonpath.jsonpath(obj, '$..book[?(@.price<10)]')
print(ret)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{
"store": {
"book": [
{
"category": "文学",
"author": "路遥",
"title": "平凡的世界",
"price": 8.95
},
{
"category": "文学",
"author": "席慕蓉",
"title": "穆斯林的葬礼",
"price": 12.99
},
{
"category": "历史",
"author": "二月河",
"title": "康熙大帝",
"isbn": "0-553-21311-3",
"price": 28.99
},
{
"category": "言情",
"author": "琼瑶",
"title": "还珠格格",
"isbn": "0-395-19395-8",
"price": 2.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
XPath JSONPath 结果
/store/book/author $.store.book[*].author 商店中所有书籍的作者
//author $..author 所有作者
/store/* $.store.* 商店里所有的东西,包括一些书和一辆红色的自行车。
/store//price $.store..price 商店中所有商品的价格。
//book[3] $..book[2] 第三本书
//book[last()] $..book[(@.length-1)] $..book[-1:] 最后一本书。
//book[position()<3] $..book[0,1] $..book[:2] 前两本书
//book[isbn] $..book[?(@.isbn)] 过滤所有具有 isbn 编号的书
//book[price<10] $..book[?(@.price<10)] 筛选所有价格低于 10 的书籍
//* $..* XML 文档中的所有元素。JSON 结构的所有成员。

示例 2:淘宝评论爬取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import urllib.request
import urllib.parse
import json
import re
import jsonpath

'''
接口
https://rate.taobao.com/feedRateList.htm?auctionNumId=559141739630&userNumId=100340983&currentPageNum=3&pageSize=20
'''

items_list = []


def main():
# 在这里搞一个循环,爬取多页的评论内容
url = 'https://rate.taobao.com/feedRateList.htm?auctionNumId=559141739630&userNumId=100340983&currentPageNum=1&pageSize=20'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)
json_text = urllib.request.urlopen(request).read().decode()

# 去除json格式字符串两边的非法字符
json_text = json_text.strip('() \n\t\r')
# print(json_text)
# 将json两边的小括号干掉,通过正则去除
# json_text = re.sub(r'\(', '', json_text)
# json_text = re.sub(r'\)', '', json_text)
# print(json_text)
# exit()
# 将json格式字符串转化为python对象
obj = json.loads(json_text)
# print(obj)
# 抓取评论内容
# 用户头像、用户名、评论内容、评论时间、手机类型
# 首先取出comments这个列表
comments_list = obj['comments']
# 遍历这个列表,依次提取每一条评论
for comment in comments_list:
# 用户头像
user = jsonpath.jsonpath(comment, '$..user')[0]
face = 'http:' + user['avatar']
# 用户名
name = user['nick']
# 评论内容
ping_content = comment['content']
# 评论时间
ping_time = comment['date']
# 手机信息
info = jsonpath.jsonpath(comment, '$..sku')[0]
# 将评论信息保存到字典中
item = {
'用户头像': face,
'用户名': name,
'评论': ping_content,
'时间': ping_time,
'信息': info,
}
items_list.append(item)


if __name__ == '__main__':
main()

string = json.dumps(items_list, ensure_ascii=False)
# 保存到文件中
with open('ping.txt', 'w', encoding='utf8') as fp:
fp.write(string)