2015年4月27日 星期一

[Python] Google 經緯度反查詢API

enter image description here
(圖片來源:http://www.ibm.com/developerworks/library/j-coordconvert/)
先前利用python寫了一個簡單的小工具接google的api來查詢住址的經緯度-[Python] Google 經緯度查詢Api.最近因為一些需求,需要從經緯度反查住址,所以就把這個小工具更新了一下.

這次更新的部分也是透過GOOGLE提供的API-ReversGeocoding,只要在網址中https://maps.googleapis.com/maps/api/geocode/json?latlng=輸入任意的經緯度,就可以傳回相關資訊.如果就那麼簡單實在是也沒啥好介紹的,但是問題出在他傳回來的json格式長這樣(API連結):
{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "277",
               "short_name" : "277",
               "types" : [ "street_number" ]
            },
            {
               "long_name" : "Bedford Avenue",
               "short_name" : "Bedford Ave",
               "types" : [ "route" ]
            },
            {
               "long_name" : "Williamsburg",
               "short_name" : "Williamsburg",
               "types" : [ "neighborhood", "political" ]
            },
            {
               "long_name" : "Brooklyn",
               "short_name" : "Brooklyn",
               "types" : [ "sublocality", "political" ]
            },
            {
               "long_name" : "Kings",
               "short_name" : "Kings",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "New York",
               "short_name" : "NY",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "United States",
               "short_name" : "US",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "11211",
               "short_name" : "11211",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "277 Bedford Avenue, Brooklyn, NY 11211, USA",
         "geometry" : {
            "location" : {
               "lat" : 40.714232,
               "lng" : -73.9612889
            },
            "location_type" : "ROOFTOP",
            "viewport" : {
               "northeast" : {
                  "lat" : 40.7155809802915,
                  "lng" : -73.9599399197085
               },
               "southwest" : {
                  "lat" : 40.7128830197085,
                  "lng" : -73.96263788029151
               }
            }
         },
         "place_id" : "ChIJd8BlQ2BZwokRAFUEcm_qrcA",
         "types" : [ "street_address" ]
      },

  ... Additional results[] ...
可以看到回傳一堆資訊,假設我們要找的地方是這個經緯度所在的國家,就在第二層的第七個位置(範例中為United States).偏偏麻煩在於每個座標傳回來的階層長得不太一樣像是這個範例
{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "人倫林道支線",
               "short_name" : "人倫林道支線",
               "types" : [ "route" ]
            },
            {
               "long_name" : "雙龍村",
               "short_name" : "雙龍村",
               "types" : [ "administrative_area_level_4", "political" ]
            },
            {
               "long_name" : "Xinyi Township",
               "short_name" : "Xinyi Township",
               "types" : [ "administrative_area_level_3", "political" ]
            },
            {
               "long_name" : "Nantou County",
               "short_name" : "Nantou County",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "Taiwan",
               "short_name" : "TW",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "556",
               "short_name" : "556",
               "types" : [ "postal_code" ]
            }
         ],
  ... Additional results[] ...     
可以看到這次的國家位置在第二層的第五個位置,所以跟地址查詢不一樣,不能使用無腦算階層的方式來查找,所以這次使用了稍微智慧一點的查找方式:
class GeocodeQueryReverse:
    def __init__(self, lat =None, lng = None, language='en'):
        url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng={0},{1}&language={2}'.format(lat, lng, language)
        response = urllib2.urlopen(url)
        self.jsonResponse = json.loads(response.read())

    def get_country(self):
        if len(self.jsonResponse["results"]) is not 0:
            for item in self.jsonResponse["results"][0]["address_components"]:
                if item["types"][0] == "country":
                    return item["long_name"]
  • 第一步當物件實體化時,同時帶入經緯度.
  • 接著get_country這個方法,不再使用算階層的方式,而使帶入for迴圈中,去查找types這個元素的值是不是country,如果是的話,就把同一層的long_name回傳
    使用方法如下:
#in python
from geocodequery import GeocodeQueryReverse
gqr = GeocodeQueryReverse(40.714224,-73.961452)
gqr.get_country() #United States
另外為了方便使用,另外做了cmd的指令
if __name__ == '__main__':
    if (len(sys.argv) != 5):
        print 'usage: geocodeQuery.py [reverse] [lat] [lng] [country/addr]'
        sys.exit(1)

    if (sys.argv[1] == 'reverse' and sys.argv[4] == 'country'):
        gqr = GeocodeQueryReverse(sys.argv[2],sys.argv[3])
        print gqr.get_country()
讓程式可以在cmd的模式下直接輸入經緯度查找.
完整程式碼可以看brynaynag0528/geocodeQuert