Résoudre une adresse physique en coordonnées GPS avec Google

Le mer. 05 octobre 2011 par Kasey

Je travaille en ce moment sur un projet nécessitant de convertir des adresses physiques en coordonnées GPS. Étant côté serveur j'ai été bien embêté pour convertir ces dernières sans passer par l'API JavaScript de Google. J'ai heureusement pu trouver une documentation (maintenant, sortir de mon historique de navigation) fournissant une URL vers un service de Google faisant cela plus que bien.

Les URLs & leur utilisation

Exemple :

http://maps.google.com/maps/api/geocode/json?address=40%20passage%20des%20panoramas,%2075002,%20paris,%20france&sensor=true

La sortie est superbe et google a même fait l'effort de réaliser un json indenté (du gros délire) :

curl -v 'http://maps.google.com/maps/api/geocode/json?address=40%20passage%20des%20panoramas,%2075002,%20paris,%20france&sensor=true'
* About to connect() to maps.google.com port 80 (#0)
*   Trying 74.125.230.74... connected
> GET /maps/api/geocode/json?address=40%20passage%20des%20panoramas,%2075002,%20paris,%20france&sensor=true HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-apple-darwin10.8.0) libcurl/7.22.0 OpenSSL/1.0.0e zlib/1.2.5 libidn/1.22
> Host: maps.google.com
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
< Date: Wed, 05 Oct 2011 13:23:30 GMT
< Expires: Thu, 06 Oct 2011 13:23:30 GMT
< Cache-Control: public, max-age=86400
< Vary: Accept-Language
< Server: mafe
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: SAMEORIGIN
< Transfer-Encoding: chunked
< 
{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "40",
               "short_name" : "40",
               "types" : [ "street_number" ]
            },
            {
               "long_name" : "Passage des Panoramas",
               "short_name" : "Passage des Panoramas",
               "types" : [ "route" ]
            },
            {
               "long_name" : "Vivienne",
               "short_name" : "Vivienne",
               "types" : [ "neighborhood", "political" ]
            },
            {
               "long_name" : "2nd arrondissement of Paris",
               "short_name" : "2nd arrondissement of Paris",
               "types" : [ "sublocality", "political" ]
            },
            {
               "long_name" : "Paris",
               "short_name" : "Paris",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Paris",
               "short_name" : "75",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" :le-de-France",
               "short_name" : "IdF",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "France",
               "short_name" : "FR",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "75002",
               "short_name" : "75002",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "40 Passage des Panoramas, 75002 Paris, France",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 48.87067050,
                  "lng" : 2.34156180
               },
               "southwest" : {
                  "lat" : 48.870670,
                  "lng" : 2.34155650
               }
            },
            "location" : {
               "lat" : 48.87067050,
               "lng" : 2.34155650
            },
            "location_type" : "RANGE_INTERPOLATED",
            "viewport" : {
               "northeast" : {
                  "lat" : 48.87201923029150,
                  "lng" : 2.342908130291502
               },
               "southwest" : {
                  "lat" : 48.86932126970850,
                  "lng" : 2.340210169708498
               }
            }
         },
         "types" : [ "street_address" ]
      }
   ],
   "status" : "OK"
}
* Connection #0 to host maps.google.com left intact
* Closing connection #0

La classe python qui vas bien

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/env python
#-*-coding: utf-8 -*-

import urllib2, cookielib, urllib, json

class GoogleResolv:
    def __init__(self,number,street,codepostal,city,country):
        self.nb = number
        self.st = street
        self.cp = codepostal
        self.ci = city
        self.cn = country
        self.lat = -1
        self.lng = -1
        self.add = -1

    def __repr__(self):
        if self.add == -1:
            return "<GoogleResolv ('%(nb)s %(st)s %(cp)s %(ci)s %(cn)s' => ('%(lat)s','%(lng)s'))>" % self.__dict__
        else:
            return "<GoogleResolv ('%(add)s' => ('%(lat)s','%(lng)s'))>" % self.__dict__

    def resolv(self):        
        cookiejar = cookielib.CookieJar()
        urlOpener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar))
        useragent = {'User-Agent':'Kasey-fetcher/1.0'}
        req = "http://maps.google.com/maps/api/geocode/json?address=%s ,%s ,%s ,%s ,%s &sensor=false" % (self.nb,self.st,self.cp,self.ci,self.cn)
        req = req.replace(' ','%20')
        request = urllib2.Request(req, None, useragent)
        url = urlOpener.open(request)
        data = json.loads(url.read())
        self.lat = data['results'][0]['geometry']['location']['lat']
        self.lng = data['results'][0]['geometry']['location']['lng']
        self.add = data['results'][0]['formatted_address'] 
        return {'lat':self.lat,'lng':self.lng}

if __name__ == "__main__":
    g = GoogleResolv("123","passage des panoramas","75002","paris","france")
    g.resolv()
    print g