当前位置:   article > 正文

Python 学习 ---> dpath、jsonpath、jsonpath-ng、json、usjon、rapidjson、orjson、序列化(pickle /msgpack)_python json path

python json path


​Github :https://github.com/json-path/JsonPath
JsonPath 在线解析:https://jsonpath.com/    https://www.jsonpath.cn/

1、像路径一样,操作嵌套字典

安装 dpath :pip install dpath

  1. import dpath.util
  2. data = {
  3. "foo": {
  4. "bar": {
  5. "a": 10,
  6. "b": 20,
  7. "c": [],
  8. "d": ['red', 'buggy', 'bumpers'],
  9. }
  10. }
  11. }
  12. print(dpath.util.get(data, "/foo/bar/d"))

2、JsonPath 解析 json

JsonPath 是用来提取指定 JSON 文档的部分内容。 许多编程语言都提供的了对 json 的解析。
JsonPath 对于 JSON 来说,相当于 XPath 对于 XML。通过使用 JsonPath 可以方便的查找节点、获取想要的数据,JsonPath 就是 Json版的XPath。

jsonpath 库

jsonpath 安装:pip install jsonpath

jsonpath-rw:JSONPath 健壮且显著扩展的Python实现,带有一个明确的AST用于元编程。
jsonpath-rw 介绍:https://pypi.org/project/dt-jsonpath-rw/
        安装:pip install dt-jsonpath-rw

JsonPath 语法要点

  • $     表示文档的根元素
  • @     表示文档的当前元素
  • .node_name 或 ['node_name']     匹配下级节点
  • [index]     检索数组中的元素。JsonPath 的索引从 0 开始计数
  • [start:end:step]     支持数组切片语法
  • *     作为通配符,匹配所有成员
  • ..     子递归通配符,匹配成员的所有子元素
  • (<expr>)     使用表达式
  • ?(<boolean expr>)    进行数据筛选

JsonPath中的 "根成员对象" 总是被引用为 $,不管它是对象还是数组。

JsonPath 使用方法:

  • 方法 1:使用 表示法:$.store.book[0].title
  • 方法 2:使用 括号 表示法:$['store']['book'][0]['title']

JsonPath 中字符串使用单引号表示,例如:$.store.book[?(@.category=='reference')]

使用 过滤

"过滤器" 是用于筛选数组的逻辑表达式。一个典型的过滤器应该是 [?(@.age > 18)],其中 @ 表示当前正在处理的项。可以使用逻辑运算符 &&|| 创建更复杂的过滤器。字符串文字 必须用 单引号双引号 括起来 ([?(@.color == 'blue')] or [?(@.color == "blue")])。

操作符描述
==左边得值 等于 右边的值 ( 注意:数字 1 不等于 字符串 '1' )
!=不等于
<小于
<=小于等于
>大于
>=大于等于
=~匹配正则表达式  [?(@.name =~ /foo.*?/i)]
in左边 in 右边 [?(@.size in ['S', 'M'])]
nin左边 not in 右边
subsetof左边是右边的一个子字符串 [?(@.sizes subsetof ['S', 'M', 'L'])]
anyof左边和右边相交 [?(@.sizes anyof ['M', 'L'])]
noneof左边和右边不相交 [?(@.sizes noneof ['M', 'L'])]
size(数组或字符串)长度
empty(数组或字符串)为空

JsonPath 表达式示例:

JsonPath ( 点击链接测试 )结果
$.store.book[*].author获取 Json 中 store下book下的所有author值
$..author获取 Json 中 所有 author 的值。
$.store.*获取 store 下所有东西( book 和 bicycle )
$.store..price获取 store下以及所有子节点下的所有 price
$..book[2]获取 book数组的第3个值
$..book[-2]获取 book数组的倒数第二个值
$..book[0,1]获取 book数组的第一、第二的值
$..book[:2]获取 book数组从索引 0 (包括) 到 索引 2 (不包括) 的所有值 
$..book[1:2]获取 book数组从索引 1 (包括) 到 索引 2 (不包括) 的所有值 
$..book[-2:]获取 book数组从索引 -2 (包括) 到 结尾 的所有值
$..book[2:]获取 book数组从索引 2 (包括) 到 结尾 的所有值
$..book[?(@.isbn)]获取 所有节点以及子节点中 book 数组包含 isbn 的所有值
$.store.book[?(@.price < 10)]获取 store下 book 数组中 price < 10 的所有值
$..book[?(@.price <= $['expensive'])]获取 所有节点以及子节点下 book 数组中 price <= expensive 的所有值
$..book[?(@.author =~ /.*REES/i)]获取所有匹配正则的 book ( 不区分大小写 )
$..*

逐层列出 json 中 的所有值,层级由外到内

$..book.length()book 数组的长度

JsonPath 和 XPath 对比

示例

代码来源于https://goessner.net/articles/JsonPath/,JSON文档如下:

  1. {
  2. "store": {
  3. "book": [{
  4. "category": "reference",
  5. "author": "Nigel Rees",
  6. "title": "Sayings of the Century",
  7. "price": 8.95
  8. }, {
  9. "category": "fiction",
  10. "author": "Evelyn Waugh",
  11. "title": "Sword of Honour",
  12. "price": 12.99
  13. }, {
  14. "category": "fiction",
  15. "author": "Herman Melville",
  16. "title": "Moby Dick",
  17. "isbn": "0-553-21311-3",
  18. "price": 8.99
  19. }, {
  20. "category": "fiction",
  21. "author": "J. R. R. Tolkien",
  22. "title": "The Lord of the Rings",
  23. "isbn": "0-395-19395-8",
  24. "price": 22.99
  25. }
  26. ],
  27. "bicycle": {
  28. "color": "red",
  29. "price": 19.95
  30. }
  31. }
  32. }

示例:

  1. import jsonpath
  2. def learn_json_path():
  3. book_store = {
  4. "store": {
  5. "book": [
  6. {
  7. "category": "reference",
  8. "author": "Nigel Rees",
  9. "title": "Sayings of the Century",
  10. "price": 8.95
  11. },
  12. {
  13. "category": "fiction",
  14. "author": "Evelyn Waugh",
  15. "title": "Sword of Honour",
  16. "price": 12.99
  17. },
  18. {
  19. "category": "fiction",
  20. "author": "Herman Melville",
  21. "title": "Moby Dick",
  22. "isbn": "0-553-21311-3",
  23. "price": 8.99
  24. },
  25. {
  26. "category": "fiction",
  27. "author": "J. R. R. Tolkien",
  28. "title": "The Lord of the Rings",
  29. "isbn": "0-395-19395-8",
  30. "price": 22.99
  31. }
  32. ],
  33. "bicycle": {
  34. "color": "red",
  35. "price": 19.95
  36. }
  37. },
  38. "expensive": 10
  39. }
  40. # print(type(book_store))
  41. # 查询store下的所有元素
  42. print(jsonpath.jsonpath(book_store, '$.store.*'))
  43. # 获取json中store下book下的所有author值
  44. print(jsonpath.jsonpath(book_store, '$.store.book[*].author'))
  45. # 获取所有json中所有author的值
  46. print(jsonpath.jsonpath(book_store, '$..author'))
  47. # 获取json中store下所有price的值
  48. print(jsonpath.jsonpath(book_store, '$.store..price'))
  49. # 获取json中book数组的第3个值
  50. print(jsonpath.jsonpath(book_store, '$.store.book[2]'))
  51. # 获取所有书
  52. print(jsonpath.jsonpath(book_store, '$..book[0:1]'))
  53. # 获取json中book数组中包含isbn的所有值
  54. print(jsonpath.jsonpath(book_store, '$..book[?(@.isbn)]'))
  55. # 获取json中book数组中price<10的所有值
  56. print(jsonpath.jsonpath(book_store, '$..book[?(@.price<10)]'))
  57. if __name__ == '__main__':
  58. learn_json_path()

示例:

  1. import json
  2. from jsonpath import jsonpath
  3. data_dict = {
  4. "family": {
  5. "parent": "John",
  6. "children": [
  7. {"name": "Alice", "age": 10},
  8. {"name": "Bob", "age": 8},
  9. {"name": "Charlie", "age": 6},
  10. {"name": "David", "age": 4}
  11. ]
  12. }
  13. }
  14. result_list_1 = jsonpath(data_dict, '$..children[?(@.name=="Charlie")]')
  15. print(result_list_1)
  16. result_list_2 = jsonpath(data_dict, '$..[?(@.name=="Charlie")]')
  17. print(result_list_2)

拉勾网城市 JSON 文件 http://www.lagou.com/lbs/getAllCitySearchLabels.json 获取所有城市。

  1. import json
  2. import jsonpath
  3. import requests
  4. url = 'http://www.lagou.com/lbs/getAllCitySearchLabels.json'
  5. custom_headers = {
  6. "Accept": "*/*",
  7. "Accept-Encoding": "gzip, deflate, br",
  8. "Accept-Language": "zh-CN,zh;q=0.9",
  9. "Cache-Control": "max-age=0",
  10. "Connection": "keep-alive",
  11. "Host": "www.lagou.com",
  12. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
  13. "(KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36"
  14. }
  15. response = requests.get(url, headers=custom_headers)
  16. json_obj = json.loads(response.text)
  17. print(json_obj)
  18. # 从根节点开始,匹配name节点
  19. city_list = jsonpath.jsonpath(json_obj, '$..name')
  20. print(city_list)
  21. print(type(city_list))
  22. # A 下面的节点
  23. jp = jsonpath.jsonpath(json_obj, '$..A.*')
  24. print(jp)
  25. # A 下面节点的name
  26. jp = jsonpath.jsonpath(json_obj, '$..A.*.name')
  27. print(jp)
  28. # C 下面节点的name
  29. jp = jsonpath.jsonpath(json_obj, '$..C..name')
  30. print(jp)
  31. # C 下面节点的第二个
  32. jp = jsonpath.jsonpath(json_obj, '$..C[1]')
  33. print(jp)
  34. # C 下面节点的第二个的name
  35. jp = jsonpath.jsonpath(json_obj, '$..C[1].name')
  36. print(jp)
  37. # C 下面节点的2到5的name
  38. jp = jsonpath.jsonpath(json_obj, '$..C[1:5].name')
  39. print(jp)
  40. # C 下面节点最后一个的name
  41. jp = jsonpath.jsonpath(json_obj, '$..C[(@.length-1)].name')
  42. print(jp)
  43. with open('city.json', 'w', encoding='utf-8') as f:
  44. content = json.dumps(city_list, ensure_ascii=False, indent=4)
  45. print(content)
  46. f.write(content)

注意事项:json.loads() 是把 Json 格式字符串解码转换成 Python 对象,如果在 json.loads 的时候出错,要注意被解码的 Json 字符的编码。
如果传入的字符串的编码不是 UTF-8 的话,需要制定字符编码的参数:encoding

jsonpath-ng 库

jsonpath-ng:https://pypi.org/project/jsonpath-ng/

jsonpath-ng 库可以对 JSON 数据进行复杂查询,包括选择父节点。比 jsonpath 库更强大。

安装:pip install --upgrade jsonpath-ng

语 法

$           根节点。
`this`     当前节点。
`foo`      foo 节点。
[ field ]   包含field字段。

        fieldname     字段名
        "fieldname"     同上,如果包含特殊字符,使用引号包括。
        'fieldname'     同上
        *             任何字段
        field , field     指定多个字段,等价于 field | field
[ idx ]     数组访问

        [*n*]    
        [start?:end?]    
        [*]

jsonpath1.jsonpath2        在 jsonpath1节点下,查找所有与jsonpath2匹配的子节点
jsonpath[whatever]          等价于 jsonpath.whatever
jsonpath1..jsonpath2       在jsonpath1节点下,查找所有与jsonpath2匹配的子孙节点
jsonpath1 where jsonpath2  匹配 jsonpath1节点有个子节点jsonpath2 的所有节点
jsonpath1 | jsonpath2      匹配 jsonpath1 和 jsonpath2 并集的任何节点

  1. import json
  2. from jsonpath_ng import jsonpath
  3. from jsonpath_ng import parse
  4. from jsonpath_ng.ext import parse as ext_parse
  5. # 假设我们有以下JSON数据
  6. json_data = json.loads("""
  7. {
  8. "store": {
  9. "book": [
  10. {
  11. "title": "Sword of Honour",
  12. "category": "fiction"
  13. },
  14. {
  15. "title": "Moby Dick",
  16. "category": "fiction"
  17. },
  18. {
  19. "title": "The Lord of the Rings",
  20. "category": "fiction"
  21. }
  22. ],
  23. "bicycle": {
  24. "color": "red",
  25. "price": 19.95
  26. }
  27. }
  28. }
  29. """)
  30. # JsonPath 表达式,选择所有category为fiction的book的父节点
  31. jsonpath_expr = ext_parse("$.store.book[?(@.category=='fiction')].title")
  32. # 执行 JsonPath 查询
  33. matches = jsonpath_expr.find(json_data)
  34. # 打印出所有符合条件的节点的父节点的标题
  35. for match in matches:
  36. print(match.value)

下面一些示例是一种更健壮的方法来创建不依赖于解析器的 JSONPath 表达式。

Root()
Slice(start=0, end=None, step=None)
Fields('foo', 'bar')
Index(42)
Child(Fields('foo'), Index(42))
Where(Slice(), Fields('subfield'))
Descendants(jsonpath, jsonpath)

要使用下面的扩展,必须从 jsonpath_ng.ext 导入。

字符串 的算术运算。操作是使用 python 运算符完成的,并允许 python 允许的类型,如果由于类型不兼容而可以执行操作,则返回 []。

{
    'cow': 'foo',
    'fish': 'bar'
}

cow + fish               返回值为 cowfish
$.cow + $.fish           返回值为 foobar
$.cow + "_" + $.fish     返回值为 foo_bar
$.cow + "_" + fish       返回值为 foo_fish

列表 的 算术运算。如果两个列表的大小相同,则可以对它们使用算术。

{'objects': [
    {'cow': 2, 'cat': 3},
    {'cow': 4, 'cat': 6}
]}

$.objects[\*].cow + $.objects[\*].cat        返回值为    [6, 9]

基本 示例

  1. from jsonpath_ng import jsonpath, parse
  2. from jsonpath_ng.jsonpath import Fields
  3. from jsonpath_ng.jsonpath import Slice
  4. json_dict = {'foo': [{'baz': 1}, {'baz': 2}]}
  5. # 一个健壮的解析器,而不仅仅是一个正则表达式。
  6. jsonpath_expr = parse('foo[*].baz')
  7. temp = [match.value for match in jsonpath_expr.find(json_dict)]
  8. print(temp)
  9. temp = [str(match.full_path) for match in jsonpath_expr.find(json_dict)]
  10. print(temp)
  11. temp = jsonpath_expr.update(json_dict, 3)
  12. print(temp)
  13. matches = jsonpath_expr.find(json_dict)
  14. matches[0].full_path.update(json_dict, 3)
  15. jsonpath_expr.filter(lambda d: True, json_dict)
  16. jsonpath_expr.filter(lambda d: d == 2, json_dict)
  17. json_dict = {'foo': [{'id': 'bizzle'}, {'baz': 3}]}
  18. jsonpath.auto_id_field = 'id'
  19. temp = [match.value for match in parse('foo[*].id').find(json_dict)]
  20. print(temp)
  21. json_dict = {'a': {'x': {'b': 1, 'c': 'number one'}, 'y': {'b': 2, 'c': 'number two'}}}
  22. temp = [match.value for match in parse('a.*.b.`parent`.c').find(json_dict)]
  23. print(temp)
  24. jsonpath_expr_direct = Fields('foo').child(Slice('*')).child(Fields('baz'))

使用 extended parser

from jsonpath_ng.ext import parse

jsonpath_expr = parse('foo[*].baz')

3、json、usjon、rapidjson、orjson

ujson:https://github.com/ultrajson/ultrajson

ujson github 上有各种 json 库对比。一般使用 json 足够,要是追求性能,推荐 ujson

4、使用 json 

json 类型特征

  • json 是一种通用的数据类型,一般情况下接口返回的数据类型都是json
  • 长得像 Python 字典,形式也是 k-v
  • 其实 json 是字符串
  • 字符串不能用 key、value 来取值,所以要先转换为 Python 的字典才可以

json 帮助

官网文档:https://docs.python.org/zh-cn/3/library/json.html

json 提供了与标准库 marshal 和 pickle 相似的API接口。

对基本的 Python 对象层次结构进行编码:

  1. import json
  2. json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
  3. print(json.dumps("\"foo\bar"))
  4. print(json.dumps('\u1234'))
  5. print(json.dumps('\\'))
  6. print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True))
  7. from io import StringIO
  8. io = StringIO()
  9. json.dump(['streaming API'], io)
  10. io.getvalue()
'
运行

紧凑编码:就是把多余的空格全部删除。有的爬虫请求中就是使用的 紧凑编码

  1. import json
  2. json.dumps([1, 2, 3, {'4': 5, '6': 7}], separators=(',', ':'))
'
运行

美化输出:

  1. import json
  2. print(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4))
'
运行

JSON解码:

  1. import json
  2. json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
  3. json.loads('"\\"foo\\bar"')
  4. from io import StringIO
  5. io = StringIO('["streaming API"]')
  6. json.load(io)
'
运行

命令行使用 json.tool 来验证并美化输出:

5、Python 序列化

pickle 模块

  • pickle 模块用于实现 序列化反序列化
  • 序列化 dumps 可以将 list、dict 等数据结构转化为二进制
  • 反序列化 loads 可以将字符串转化为 list、dict

数据结构(可以是列表、字典等)转成字符串:dumps()方法:将一个数据结构编码为二进制数据

  1. import pickle
  2. data_dict = {'name': 'king', 'age': '100'}
  3. data_dict_list = [
  4. {'name': 'king', 'age': '100'},
  5. {'name': 'king', 'age': '100'}
  6. ]
  7. data_string_1 = pickle.dumps(data_dict)
  8. print(type(data_string_1))
  9. print(data_string_1)
  10. data_string_2 = pickle.dumps(data_dict)
  11. print(type(data_string_2))
  12. print(data_string_2)
  13. temp = pickle.loads(data_string_2)
  14. print(type(temp))
  15. print(temp)
'
运行

msgpack 模块

安装 msgpack :pip install msgpack

msgpack 类型特征

  • msgpack 是一种有效的二进制序列化格式。它使您可以在多种语言(如JSON)之间交换数据。但是它更快,更小。
  • 序列化 packb 可以将 list、dict 等数据结构转化为二进制 ( packb 别名为 dumps )
  • 反序列化 loads 可以将字符串转化为 list、dict ( unpackb 别名为 loads )
  1. import msgpack
  2. data_dict = {'name': 'king', 'age': '100'}
  3. data_dict_list = [
  4. {'name': 'king', 'age': '100'},
  5. {'name': 'king', 'age': '100'}
  6. ]
  7. data_string_1 = msgpack.dumps(data_dict, use_bin_type=True)
  8. print(type(data_string_1))
  9. print(data_string_1)
  10. temp_1 = msgpack.loads(data_string_1, use_list=False)
  11. print(temp_1)
  12. data_string_2 = msgpack.dumps(data_dict_list)
  13. print(type(data_string_2))
  14. print(data_string_2)

示例:

  1. import datetime
  2. import msgpack
  3. useful_dict = {
  4. "id": 1,
  5. "created": datetime.datetime.now(),
  6. }
  7. def decode_datetime(obj):
  8. if b'__datetime__' in obj:
  9. obj = datetime.datetime.strptime(obj["as_str"], "%Y%m%dT%H:%M:%S.%f")
  10. return obj
  11. def encode_datetime(obj):
  12. if isinstance(obj, datetime.datetime):
  13. return {'__datetime__': True, 'as_str': obj.strftime("%Y%m%dT%H:%M:%S.%f")}
  14. return obj
  15. packed_dict = msgpack.packb(useful_dict, default=encode_datetime, use_bin_type=True)
  16. this_dict_again = msgpack.unpackb(packed_dict, object_hook=decode_datetime, raw=False)
  17. print(packed_dict)
  18. print(this_dict_again)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/927117
推荐阅读
相关标签
  

闽ICP备14008679号