使用 python 将多个 JSON 对象作为一个对象写入单个文件
Writing multiple JSON objects as one object to a single file with python
我正在使用 python 攻击工头 API 以收集工头知道的所有主机的一些信息。不幸的是,v1 工头 API 中没有 get-all-hosts-facts(或类似的东西),所以我不得不遍历所有主机并获取信息。这样做让我遇到了一个恼人的问题。每次调用给定主机 return 一个 JSON 对象,如下所示:
{
"host1.com": {
"apt_update_last_success": "1452187711",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
}
}
这完全没问题,当我追加下一位主持人的信息时,问题就出现了。然后我得到一个看起来像这样的 json 文件:
{
"host1.com": {
"apt_update_last_success": "1452187711",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
}
}{
"host2.com": {
"apt_update_last_success": "1452703454",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
}
}
这是执行此操作的代码:
for i in hosts_data:
log.info("Gathering host facts for host: {}".format(i['host']['name']))
try:
facts = requests.get(foreman_host+api+"hosts/{}/facts".format(i['host']['id']), auth=(username, password))
if hosts.status_code != 200:
log.error("Unable to connect to Foreman! Got retcode '{}' and error message '{}'"
.format(hosts.status_code, hosts.text))
sys.exit(1)
except requests.exceptions.RequestException as e:
log.error(e)
facts_data = json.loads(facts.text)
log.debug(facts_data)
with open(results_file, 'a') as f:
f.write(json.dumps(facts_data, sort_keys=True, indent=4))
这是我需要的文件:
{
"host1.com": {
"apt_update_last_success": "1452187711",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
},
"host2.com": {
"apt_update_last_success": "1452703454",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
}
}
不要在循环中写入 json,而是将数据插入具有正确结构的 dict
。然后在循环结束时将该字典写入 json。
这假设您的数据集适合内存。
最好assemble把你所有的数据写成一个dict,然后一次写出来,而不是每次都在循环中。
d = {}
for i in hosts_data:
log.info("Gathering host facts for host: {}".format(i['host']['name']))
try:
facts = requests.get(foreman_host+api+"hosts/{}/facts".format(i['host']['id']), auth=(username, password))
if hosts.status_code != 200:
log.error("Unable to connect to Foreman! Got retcode '{}' and error message '{}'"
.format(hosts.status_code, hosts.text))
sys.exit(1)
except requests.exceptions.RequestException as e:
log.error(e)
facts_data = json.loads(facts.text)
log.debug(facts_data)
d.update(facts_data) #add to dict
# write everything at the end
with open(results_file, 'a') as f:
f.write(json.dumps(d, sort_keys=True, indent=4))
对于 safety/consistency,您需要加载旧数据,对其进行变异,然后将其写回。
将当前的with
和write
改为:
# If file guaranteed to exist, can use r+ and avoid initial seek
with open(results_file, 'a+') as f:
f.seek(0)
combined_facts = json.load(f)
combined_facts.update(facts_data)
f.seek(0)
json.dump(combined_facts, f, sort_keys=True, indent=4)
f.truncate() # In case new JSON encoding smaller, e.g. due to replaced key
注意:如果可能,您希望使用 来尽量减少不必要的 I/O,如果数据检索应该零碎地完成,那么您就会这样做,并立即更新每件商品可用时。
仅供参考,不安全的方法基本上是找到尾随的大括号,将其删除,然后写出一个逗号,后跟新的 JSON(从 JSON 表示中删除前导大括号).它 I/O 密集程度要低得多,但也不太安全,不会清除重复项,不会对主机进行排序,根本不会验证输入文件等等。所以不要这样做。
我正在使用 python 攻击工头 API 以收集工头知道的所有主机的一些信息。不幸的是,v1 工头 API 中没有 get-all-hosts-facts(或类似的东西),所以我不得不遍历所有主机并获取信息。这样做让我遇到了一个恼人的问题。每次调用给定主机 return 一个 JSON 对象,如下所示:
{
"host1.com": {
"apt_update_last_success": "1452187711",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
}
}
这完全没问题,当我追加下一位主持人的信息时,问题就出现了。然后我得到一个看起来像这样的 json 文件:
{
"host1.com": {
"apt_update_last_success": "1452187711",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
}
}{
"host2.com": {
"apt_update_last_success": "1452703454",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
}
}
这是执行此操作的代码:
for i in hosts_data:
log.info("Gathering host facts for host: {}".format(i['host']['name']))
try:
facts = requests.get(foreman_host+api+"hosts/{}/facts".format(i['host']['id']), auth=(username, password))
if hosts.status_code != 200:
log.error("Unable to connect to Foreman! Got retcode '{}' and error message '{}'"
.format(hosts.status_code, hosts.text))
sys.exit(1)
except requests.exceptions.RequestException as e:
log.error(e)
facts_data = json.loads(facts.text)
log.debug(facts_data)
with open(results_file, 'a') as f:
f.write(json.dumps(facts_data, sort_keys=True, indent=4))
这是我需要的文件:
{
"host1.com": {
"apt_update_last_success": "1452187711",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
},
"host2.com": {
"apt_update_last_success": "1452703454",
"architecture": "amd64",
"augeasversion": "1.2.0",
"bios_release_date": "06/03/2015",
"bios_vendor": "Dell Inc."
}
}
不要在循环中写入 json,而是将数据插入具有正确结构的 dict
。然后在循环结束时将该字典写入 json。
这假设您的数据集适合内存。
最好assemble把你所有的数据写成一个dict,然后一次写出来,而不是每次都在循环中。
d = {}
for i in hosts_data:
log.info("Gathering host facts for host: {}".format(i['host']['name']))
try:
facts = requests.get(foreman_host+api+"hosts/{}/facts".format(i['host']['id']), auth=(username, password))
if hosts.status_code != 200:
log.error("Unable to connect to Foreman! Got retcode '{}' and error message '{}'"
.format(hosts.status_code, hosts.text))
sys.exit(1)
except requests.exceptions.RequestException as e:
log.error(e)
facts_data = json.loads(facts.text)
log.debug(facts_data)
d.update(facts_data) #add to dict
# write everything at the end
with open(results_file, 'a') as f:
f.write(json.dumps(d, sort_keys=True, indent=4))
对于 safety/consistency,您需要加载旧数据,对其进行变异,然后将其写回。
将当前的with
和write
改为:
# If file guaranteed to exist, can use r+ and avoid initial seek
with open(results_file, 'a+') as f:
f.seek(0)
combined_facts = json.load(f)
combined_facts.update(facts_data)
f.seek(0)
json.dump(combined_facts, f, sort_keys=True, indent=4)
f.truncate() # In case new JSON encoding smaller, e.g. due to replaced key
注意:如果可能,您希望使用
仅供参考,不安全的方法基本上是找到尾随的大括号,将其删除,然后写出一个逗号,后跟新的 JSON(从 JSON 表示中删除前导大括号).它 I/O 密集程度要低得多,但也不太安全,不会清除重复项,不会对主机进行排序,根本不会验证输入文件等等。所以不要这样做。