我在使用公共API
www.gpcontract.co.uk
填充代表英国卫生组织层次结构的大型可变嵌套字典。
一些背景信息
最高级别是四个英国国家(英格兰、苏格兰、威尔士和北爱尔兰),然后是区域组织,一直到各个诊所。每个国家的等级制度的深度各不相同,并可能随年份而变化。每个组织都有一个名称、组织代码和字典,列出其子组织。
不幸的是,完整的嵌套层次结构在API中不可用,而是调用
http://www.gpcontract.co.uk/api/children/[organisation code]/[year]
将返回任何其他组织的直接子组织。
为了在我的应用程序中轻松导航层次结构,我想生成一个完整层次结构的脱机词典(每年一次),该词典将使用
pickle
与应用程序捆绑在一起。
获取这意味着许多API调用,并且我在将返回的JSON转换为我需要的Dictionary对象时遇到了困难。
下面是层次结构中一个很小的部分的例子(我只展示了一个单独的子组织作为例子)。
JSON层次结构示例
{
"eng": {
"name": "England",
"orgcode": "eng",
"children": {}
},
"sco": {
"name": "Scotland",
"orgcode": "sco",
"children": {}
},
"wal": {
"name": "Wales",
"orgcode": "wal",
"children": {}
},
"nir": {
"name": "Northern Ireland",
"orgcode": "nir",
"children": {
"blcg": {
"name": "Belfast Local Commissioning Group",
"orgcode": "blcg",
"children": {
"abc": {
"name": "Random Clinic",
"orgcode": "abc",
"children": {}
}
}
}
}
}
}
下面是我用来调用API并填充字典的脚本:
我的剧本
import json, pickle, urllib.request, urllib.error, urllib.parse
# Organisation hierarchy may vary between years. Set the year here.
year = 2017
# This function returns a list containing a dictionary for each child organisation with keys for name and orgcode
def get_child_orgs(orgcode, year):
orgcode = str(orgcode)
year = str(year)
# Correct 4-digit year to 2-digit
if len(year) > 2:
year = year[2:]
try:
child_data = json.loads(urllib.request.urlopen('http://www.gpcontract.co.uk/api/children/' + str(orgcode) + '/' + year).read())
output = []
if child_data != []:
for item in child_data['children']:
output.append({'name' : item['name'], 'orgcode' : str(item['orgcode']).lower(), 'children' : {}})
return output
except urllib.error.HTTPError:
print('HTTP error!')
except:
print('Other error!')
# I start with a template of the top level of the hierarchy and then populate it
hierarchy = {'eng' : {'name' : 'England', 'orgcode' : 'eng', 'children' : {}}, 'nir' : {'name' : 'Northern Ireland', 'orgcode' : 'nir', 'children' : {}}, 'sco' : {'name' : 'Scotland', 'orgcode' : 'sco', 'children' : {}}, 'wal' : {'name' : 'Wales', 'orgcode' : 'wal', 'children' : {}}}
print('Loading data...\n')
# Here I use nested for loops to make API calls and populate the dictionary down the levels of the hierarchy. The bottom level contains the most items.
for country in ('eng', 'nir', 'sco', 'wal'):
for item1 in get_child_orgs(country, year):
hierarchy[country]['children'][item1['orgcode']] = item1
for item2 in get_child_orgs(item1['orgcode'], year):
hierarchy[country]['children'][item1['orgcode']]['children'][item2['orgcode']] = item2
# Only England and Wales hierarchies go deeper than this
if country in ('eng', 'wal'):
level3 = get_child_orgs(item2['orgcode'], year)
# Check not empty array
if level3 != []:
for item3 in level3:
hierarchy[country]['children'][item1['orgcode']]['children'][item2['orgcode']]['children'][item3['orgcode']] = item3
level4 = get_child_orgs(item3['orgcode'], year)
# Check not empty array
if level4 != []:
for item4 in level4:
hierarchy[country]['children'][item1['orgcode']]['children'][item2['orgcode']]['children'][item3['orgcode']]['children'][item4['orgcode']] = item4
# Save the completed hierarchy with pickle
file_name = 'hierarchy_' + str(year) + '.dat'
with open(file_name, 'wb') as out_file:
pickle.dump(hierarchy, out_file)
print('Success!')
问题
这似乎在大多数情况下都有效,但当嵌套的for循环返回“nonetype is not iterable error”时,它会感觉很糟糕,有时会崩溃。我意识到这会进行大量的API调用,并且需要几分钟的时间才能运行,但是我看不到解决这一问题的方法,因为我希望完成的层次结构可以脱机使用,以便用户快速搜索数据。然后,我将以稍微不同的方式使用API来获取所选组织的实际医疗保健数据。
我的问题
是否有一种更清洁、更灵活的方法来适应组织层次结构的可变嵌套?
有没有一种方法可以更快地做到这一点?
我在JSON方面相对缺乏经验,因此任何帮助都会受到感激。