如何使用Python、JSON和Google Maps在服务器端进行反向地理编码?

6
我正在尝试进行服务器端的反向地理编码,以获取JSON响应,现在我想从JSON响应中获取2或3个变量:
例如,我想解析以下数据,并以此结束。 administrative_area_level_1 = 'Stockholm'
这是我获取JSON的Python代码,现在我想知道如何解析它以获取只有 - 行政区域级别1长名称(即州或地区名称) - 地方长名称(即城市名称) - 解析我的JSON的方法
我可以解析它,但它并不总是出现为administrative_area_1:
jsondata ["results"] [0] ["address_components"] [5] ["long_name"]
上面的行正确地输出了纽约的一个点的“New York”,但对于斯德哥尔摩,它输出了邮政城市,即Johanneshow,而不是行政区域1(地区/州)。 那么如何保证该函数始终返回administrative_area_1,最好不用循环?
我希望它能像以下示例一样工作,并直接访问国家,地区和城市:
logging.info("country:"+str(jsondata["results"][9]["formatted_address"]))
logging.info("administrative_area_level_1:"+str(jsondata["results"][8]["formatted_address"]))
logging.info("locality:"+str(jsondata["results"][8]["formatted_address"]))

谢谢您的提前帮助。

更新

这里有一个很好的答案,给出了我期望的结果。在等待答案的同时,我也尝试自己实现了一个解决方案,看起来可以完成它:

jsondata = json.load(urllib2.urlopen('http://maps.googleapis.com/maps/api/geocode/json?latlng='+str(ad.geopt.lat)+','+str(ad.geopt.lon)+'&sensor=false'))
logging.info("geography:"+str(jsondata["results"][1]["formatted_address"]))
region = None
city = None
for result in jsondata["results"]:
  #logging.info("result:"+str(result))
  for component in result["address_components"]:
    logging.info("components:"+str(component))
    logging.info("components type:"+str(component["types"]))
    if 'administrative_area_level_1' in component["types"]:
      #logging.info(unicode('found admin area:%s' % component["long_name"]))
      region = component["long_name"]
    if 'locality' in component["types"]:
      logging.info("found locality:"+str(component["long_name"]))
      city = component["long_name"]

1个回答

14

处理响应

无需解析JSON - 它已经被json.load()解析并以Python数据结构返回。像使用简单字典一样使用它,其中包含列表或不同的字典。

访问响应中需要的部分

要访问您要处理的数据,请使用以下方法:

jsondata['results'][0]['address_components']

这是包含所有地理名称信息的地方:

[{u'long_name': u'Södra Länken', u'types': [u'route'], u'short_name': u'Södra Länken'}, {u'long_name': u'Stockholm', u'types': [u'locality', u'political'], u'short_name': u'Stockholm'}, {u'long_name': u'Stockholm', u'types': [u'administrative_area_level_1', u'political'], u'short_name': u'Stockholm'}, {u'long_name': u'Sweden', u'types': [u'country', u'political'], u'short_name': u'SE'}, {u'long_name': u'12146', u'types': [u'postal_code'], u'short_name': u'12146'}, {u'long_name': u'Johanneshov', u'types': [u'postal_town'], u'short_name': u'Johanneshov'}]

筛选你需要的数据

正如你所看到的,有许多你不需要的数据,但你只想要localityadministrative_area_level_1信息。你可以使用Python中的filter()函数过滤数据,像这样:

>>> mydata = jsondata['results'][0]['address_components']
>>> types = ['locality', 'administrative_area_level_1']
>>> geonames = filter(lambda x: len(set(x['types']).intersection(types)), mydata)

基本上,您只获取具有“locality”或“administrative_area_level_1”在其“types”列表中的元素。执行上述操作后,geonames将是包含所需字典的列表:

[{u'long_name': u'Stockholm', u'types': [u'locality', u'political'], u'short_name': u'Stockholm'}, {u'long_name': u'Stockholm', u'types': [u'administrative_area_level_1', u'political'], u'short_name': u'Stockholm'}]

显示数据

要显示它们的名称,您可以例如遍历它们,显示long_name和相应的types值:

>>> for geoname in geonames:
    common_types = set(geoname['types']).intersection(set(types))
    print '{} ({})'.format(geoname['long_name'], str(', '.join(common_types)))


Stockholm (locality)
Stockholm (administrative_area_level_1)

这符合你的预期吗?

完整代码

代码可能如下所示:

import json
import urllib2

def get_geonames(lat, lng, types):
    url = 'http://maps.googleapis.com/maps/api/geocode/json' + \
            '?latlng={},{}&sensor=false'.format(lat, lng)
    jsondata = json.load(urllib2.urlopen(url))
    address_comps = jsondata['results'][0]['address_components']
    filter_method = lambda x: len(set(x['types']).intersection(types))
    return filter(filter_method, address_comps)

lat, lng = 59.3, 18.1
types = ['locality', 'administrative_area_level_1']

# Display all geographical names along with their types
for geoname in get_geonames(lat, lng, types):
    common_types = set(geoname['types']).intersection(set(types))
    print '{} ({})'.format(geoname['long_name'], ', '.join(common_types))

非常感谢!同时,我也开发了一个解决方案,可以过滤掉地区和行政区域级别1,这样我们就可以比较这两个解决方案。我正在更新问题,加入我的“解决方案”,并且我也会尝试这个答案中的方法。基本上,我是通过循环结果和类型来查找匹配项,然后将这些匹配项分配给变量区域和城市。谢谢! - Niklas Rosencrantz
1
@Nickle:你的解决方案也应该可以工作! :) 问题在于我注重代码的可读性、长度和可重用性——它使用filter()而不是大循环,使用lambda而不是条件检查,使用格式化而不是连接。最后一个(字符串格式化)可以极大地提高代码的可读性。但正如我所说,它应该可以工作 :) - Tadeck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接