浅谈JSON数据格式用以Paramiko和Netmiko的案例
〇、致谢
非常感谢盛哥 @朱嘉盛 ,在知乎专栏 《网工手艺》 中对Python处理结构化数据方法的梳理和分享:
一、JSON数据格式
JSON全称 JavaScript Object Notation ,是一种结构化的数据格式。也是一种完全独立于编程语言之外的文本存储、交换格式。
1、JSON语法规范
(1)json对象由key/value对组成;
(2)json对象必须在一组大括号{}内书写;
(3)json对象,key必须是 字符串 ,value可以是字符串、数字、布尔值、数组[]、对象、null;
{
"router_01": [
"router_01",
"admin",
"cisco",
"192.168.47.1"
"router_02": [
"router_02",
"admin",
"cisco",
"192.168.47.2"
"router_03": [
"router_03",
"admin",
"cisco",
"192.168.47.3"
}
(4)json对象是可以嵌套的,即value也可以由另一组对象嵌套组成:
{
"name": "R1",
"device_info": {
"device_type": "cisco",
"username": "admin",
"password": "cisco",
"ip": "192.168.47.1"
}
(5)json对象中,value如果由数组[]构成,那么数组[]的内部,不能包含key/value对;
(6)多个json对象,可以放到一个数组[]中。
2、JSON格式辨析
(1) 错误格式 ,因为“device_info”这个key对应的value使用了数组[],数组内部不能包含key/value对。
{
"name": "R1",
"device_info": [
"device_type": "cisco",
"username": "admin",
"password": "cisco",
"ip": "192.168.47.1"
] # 错误格式,数组中[]不能放入key/value对
}
(2) 正确格式 ,因为“device_info”这个key对应的value使用了json对象嵌套(另一组key/value对)
{
"name": "R1",
"device_info":{
"device_type": "cisco",
"username": "admin",
"password": "cisco",
"ip": "192.168.47.1"
} # 正确格式,value可以使用JSON对象嵌套(key/value嵌套)
}
(3) 错误格式 ,{}中,包含不正确的json对象(key/value对)
{
"router_01":
"router_01",
"admin",
"cisco",
"192.168.47.1"
} # 错误格式,JSON对象{}内部,必须是key/value对
(4) 正确格式 ,{}中,如果value有多个值,可以用数组收纳
{
"router_01": [
"router_01",
"admin",
"cisco",
"192.168.47.1"
] # 正确格式,value可以用数组容纳多个值
}
(5) 错误格式 ,json对象{}中,不能再包含多个JSON对象{}
{
"name": "R1",
"device_info":{
"device_type": "cisco",
"username": "admin",
"password": "cisco",
"ip": "192.168.47.1"
"name": "R2",
"device_info":{
"device_type": "cisco",
"username": "admin",
"password": "cisco",
"ip": "192.168.47.1"
} # 错误格式,JSON对象{}中,不能再包含多个JSON对象{}
(6) 正确格式 ,多个json对象{},可以放到一个数组中
[
"name": "R1",
"device_info":{
"device_type": "cisco",
"username": "admin",
"password": "cisco",
"ip": "192.168.47.1"
"name": "R2",
"device_info":{
"device_type": "cisco",
"username": "admin",
"password": "cisco",
"ip": "192.168.47.1"
] # 正确格式,JSON的多个对像{},可以用数组容纳
(7)错误格式,{}中的json对象的key,必须是字符串
{
# 错误格式,router_01并不是字符串,需要用“”引起来当字符串
router_01: [
"router_01",
"admin",
"cisco",
"192.168.47.1"
}
二、JSON用于Paramiko/Netmiko的简单案例
很多同行朋友,在使用Paramiko、Netmiko做自动化实验的时候,往往受制于非结构化数据。
比如,在使用Netmiko时,需要为ConnectHandler函数传一个 字典 参数,该字典包含了device_type、username、password、ip等数据。这就让部分同行朋友“恨如头醋” ,由于device_type的限制,部分同行朋友往往对Netmiko的“异构能力”产生“质疑”。
其实,只要掌握了结构化数据的知识,这样的烦恼就能迎刃而解。
1、Paramiko案例
熟悉DevNet的朋友可能都知道Python中大名鼎鼎的Paramiko库,如果要使用Paramiko库来操作网络设备,那么必须用到SSH登录名、SSH登录密码、SSH登录IP地址等数据。其实,就可以用结构化的数据格式来组织,比如,用JSON来组织。
sw_info.json
{
"router_01": [
"router_01",
"admin",
"cisco",
"192.168.47.1"
"router_02": [
"router_02",
"admin",
"cisco",
"192.168.47.2"
"router_03": [
"router_03",
"admin",
"cisco",
"192.168.47.3"
}
使用python自带的json库,来处理sw_info.json,Python自带的json库是很容易把json格式的文件转换成字典的。利用这个特性,就可以根据字典的特性来处理相关的数据。注意json.load和json.loads的区别。 盛哥 @朱嘉盛 在他的《 朱嘉盛:网络工程师Python数据存储(第2节,JSON文件) 》一文中,有过很精彩的助记总结:带s就是处理字符串的。不带s的就是处理文件的。
#! /usr/bin/env python3
# _*_ coding: utf-8 _*_
import json
with open('sw_info.json', encoding='utf-8') as f:
template = f.read() # 读取sw_info.json为字符串
print(type(template))
print(template)
sw_date = json.loads(template) # 使用loads字符串读取成字典,注意这里使用的是带s的loads,处理的就是字符串
print(type(sw_date)) # 查看是否被处理成了字典
pprint(sw_date) # 漂亮打印,打印出字典的内容
print('\n')
# 遍历字典,把key读取出来
for key in sw_date.keys():
# 利用key,取出value列表,利用列表进行多重歌值
filename, username, password, ip = sw_date[key]
# 打印出多重赋值的变量内容
print(filename)
print(username)
print(password)
print(ip)
print('\n')
运行结果
username@usernamedeMacBookPro1 Downloads % /usr/bin/env python3 "/Users/username/Downloads/json_test.py"
<class 'str'>
('{\n'
'\t"router_01": [\n'
'\t\t"router_01",\n'
'\t\t"admin",\n'
'\t\t"cisco",\n'
'\t\t"192.168.47.1"\n'
'\t],\n'
'\t"router_02": [\n'
'\t\t"router_02",\n'
'\t\t"admin",\n'
'\t\t"cisco",\n'
'\t\t"192.168.47.2"\n'
'\t],\n'
'\t"router_03": [\n'
'\t\t"router_03",\n'
'\t\t"admin",\n'
'\t\t"cisco",\n'
'\t\t"192.168.47.3"\n'
'\t]\n'
'}\n')
<class 'dict'>
{'router_01': ['router_01', 'admin', 'cisco', '192.168.47.1'],
'router_02': ['router_02', 'admin', 'cisco', '192.168.47.2'],
'router_03': ['router_03', 'admin', 'cisco', '192.168.47.3']}
# 多个设备的信息,都可以直接用字典value多重赋值
router_01
admin
cisco
192.168.47.1
router_02
admin
cisco
192.168.47.2
router_03
admin
cisco
192.168.47.3
2、Netmiko案例
dev_info.json
[
"name": "R1",
"device_info": {
"device_type": "cisco_ios",
"username": "admin",
"password": "cisco",
"ip": "192.168.47.10"
"name": "R2",
"device_info": {
"device_type": "huawei",
"username": "admin",
"password": "huawei",
"ip": "192.168.47.20"
]
依然使用python自带的json库,来处理这些数据,利用json.load函数,直接把json文件读取成列表,然后再进行处理。
#! /usr/bin/env python3
# _*_ coding: utf-8 _*_
import json
from pprint import pprint
with open('dev_info.json') as f:
template = json.load(f) # 因为读取的是json文件,所以要使用不带s的load
print(type(template)) # 查看json.load读取的数据类型,注意,这是列表
pprint(template) # 漂亮打印出列表的内容
print('\n')
# 从列表中把字典遍历出来
for dict_info in template:
for key in dict_info.keys():
if 'device_info' == key:
dict_netmiko_connecthandler = dict_info['device_info']
pprint(dict_netmiko_connecthandler)
print('\n')
运行结果
username@usernamedeMacBookPro1 Downloads % /usr/bin/env python3 "/Users/username/Downloads/tempCodeRunnerFile.py"
<class 'list'>
[{'device_info': {'device_type': 'cisco_ios',
'ip': '192.168.47.10',
'password': 'cisco',
'username': 'admin'},
'name': 'R1'},
{'device_info': {'device_type': 'huawei',
'ip': '192.168.47.20',
'password': 'huawei',
'username': 'admin'},
'name': 'R2'}]
# 以下字典,可以直接传给Netmiko的ConnectHandler函数,实现“异构”
{'device_type': 'cisco_ios',
'ip': '192.168.47.10',
'password': 'cisco',
'username': 'admin'}