Skip to Content

Nous adressons toutes nos pensées à la famille de notre ami Jérôme !

http://www.forumsig.org/showthread.php/43488-Disparition-de-Phoenix

Python: géocodage - géolocalisation


pythonGéocoder en Python est très facile, quelques lignes de code suffisent une fois que l'on connait les détails des services offerts par les principaux sites de géocodage/géolocalisation gratuit : Google, Yahoo, Geonames, Mediawiki et autres.

Principes

Prenons, par exemple, le service de géocodage de Google. Les Google Maps API Services (code.google.com/intl/en/apis/maps/documentation/geocoding) indiquent la manière d'interroger le service web et quels sont les résultats que l'on peut obtenir avec leur format (json, cvs, xml et kml).

L'adresse interrogée est : "Place de l'Université 1, 1348 Louvain-la-Neuve" (en Belgique).

L'interrogation se fait par l’URL suivante :

maps.google.com/maps/geo?q=Place%20de%20l%27Universit%C3%A9%2C%201%2C%201348%2C%20Louvain-la-Neuve&output=json&api_key=

L'important est le terme output= qui permet de préciser le format désiré de réponse, json,  csv,  xml ou kml.

Commençons par le résultat au format json (format par défaut):

{
"name": "Place de l'Université 1, 1348 Louvain-la-Neuve",
"Status": {
"code": 200,
"request": "geocode"
},
"Placemark": [ {
"id": "p1",
"address": "Place de l'Université, 1348 Louvain-La-Neuve, Belgique",
"AddressDetails": {
"Accuracy" : 6, "Country" : { "AdministrativeArea" : { "AdministrativeAreaName" : "Région Wallonne", "SubAdministrativeArea" : { "Locality" : { "DependentLocality" : { "DependentLocalityName" : "Louvain-la-Neuve", "PostalCode" : { "PostalCodeNumber" : "1348" }, "Thoroughfare" : { "ThoroughfareName" : "Place de l'Université" } }, "LocalityName" : "Louvain-La-Neuve" }, "SubAdministrativeAreaName" : "Brabant Wallon" } }, "CountryName" : "Belgique", "CountryNameCode" : "BE" } }, "ExtendedData": { "LatLonBox": { "north": 50.6731662, "south": 50.6668709, "east": 4.6184483, "west": 4.6121531 } }, "Point": { "coordinates": [ 4.6151754, 50.6701607, 0 ]
}
} ]
}

Les principaux éléments obtenus sont :

La réponse au format csv :

200,6,50.6701607,4.6151754

Beaucoup plus courte, sans explication, mais les données obtenues sont maintenant connues. Les résultats au format xml ou kml sont équivalents à celui de json, à la différence que le choix kml provoque le téléchargement du fichier kml.

Python seul

Maintenant, avec Python, la démarche est très simple

Pour le format csv:

import urllib
def geocode(addr, api_key=''):
        url = "http://maps.google.com/maps/geo?q=%s&output=csv&api_key=%s" % (urllib.quote(addr), urllib.quote(api_key))
        coord = urllib.urlopen(url).read().split(',')
        coortext = 'lat: %s,long: %s' % (coord[2],coord[3])
        return coortext
coordonnees = geocode("Place de l'Université 1, 1348 Louvain-la-Neuve")
print coordonnees
lat: 50.6701607 long: 4.6151754

Pour le format json (d'après gdallaire.net/blog/) :

Les versions de Python supérieures à la 2.5.x possèdent le module/bibliothèque json dans la distribution standard. Pour les autres, il suffit d'installer simplejson

import urllib
import json ou import simplejson as json (suivant les cas)
def geocode(addr, api_key=''):
        url = "http://maps.google.com/maps/geo?q=%s&output=json&api_key=%s" % (urllib.quote(addr), urllib.quote(api_key))
        data = urllib.urlopen(url).read()
        return json.loads(data)['Placemark'][0]['Point']['coordinates']
data = geocode("Place de l'Université 1, 1348 Louvain-la-Neuve")
print "lat:%s long:%s" % (data[1], data[0])
lat: 50.6701607  long:4.6151754

Traiter le résultat xml est tout aussi facile. Google, grand utilisateur et promoteur de Python, propose son propre module pour le faire gmaps-samples.googlecode.com/svn/trunk/articles-kmlgeocode/geocoding_for_kml.py.

Il est évident que la procédure doit être améliorée pour traiter les erreurs (échec du géocodage,...) ou pour interroger d'autres sites de géolocalisation. Ce dernier point est traité par www.paolocorti.net/2009/10/14/geocoding-with-geopy/ qui illustre les divers formats qui peuvent être reçus.

Heureusement, des développeurs Python ont fait le travail pour nous avec des bibliothèques comme Googlemaps (limité à Google) ou Geopy (plusieurs services).

Leur syntaxe est équivalente (en théorie avec Google, il faudrait renseigner votre clé api, mais en pratique elle n'est pas toujours nécessaire, ce qui n'est pas le cas avec Yahoo ou autre).

Python avec le module geopy

from geopy import geocoders
g=geocoders.Google('éventuellement votre clé api Google')
place, (lat, lng) = g.geocode("Place de l'Université 1, 1348, Louvain-la-Neuve")
print "%s: %.5f, %.5f" % (place, lat, lng)
Place de l'Université, 1348 Ottignies-Louvain-la-Neuve, Belgium: 50.67016, 4.61518

Geopy permet d'interroger de la même manière les autres services de geocodage (ici le Yahoo Geocoding Web Service):

y = geocoders.Yahoo('votre clé api yahoo')
place, (lat, lng) = y.geocode("Place de l'Université 1, 1348, Louvain-la-Neuve") 
print "%s: %.5f, %.5f" % (place, lat, lng)
Place De l'Université 1, 1348 Louvain-la-Neuve, Belgium, BE: 50.66990, 4.61566  

puis Geonames et autres, voir code.google.com/p/geopy/wiki/GettingStarted

La bibliothèque permet aussi d'obtenir éventuellement plusieurs géolocalisations par demande ou de calculer des distances avec 2 algorithmes:

from geopy import distance
_, lln = g.geocode('Louvain-la-Neuve')
_, Paris = g.geocode('Paris')

#avec l'algorithme GreatCircleDistance (fr.wikipedia.org/wiki/Distance_du_grand_cercle)
distance.distance = distance.GreatCircleDistance
distance.distance(lln, Paris).km
256.58343152506433

#avec l'algorithme de Vincenty (en.wikipedia.org/wiki/Vincenty%27s_formulae)
distance.VincentyDistance.ELLIPSOID = 'wgs-84'
distance.distance(lln, Paris).km
256.58343152506433

 Puis de manipuler ces distances:

d = distance.distance
_, Lille = g.geocode('Lille')
(d(lln, Lille) + d(Lille,Paris)).km
310.65819253714375

Geopy permet d'autres traitements comme le traitement des fichiers gpx ou le géocodage inverse (le "Reverse geocoding" permet d'obtenir l'adresse la plus proche d'une localisation),  mais nous allons l'appliquer avec la bibliothèque suivante.

Python avec le module googlemaps

from googlemaps import GoogleMaps
gmaps = GoogleMaps()
addresse = "Place de l'Université 1, 1348 Ottignies-Louvain-la-Neuve"
lat, lng = gmaps.address_to_latlng(addresse)
print lat, lng
50.6701607 4.6151754

Pour le "Reverse geocoding",  du fait de sa conception, il faut un niveau de précision (Accuracy) de 8 ou 9 sinon des surprises peuvent arriver ( puisque Google va chercher les adresses précises qu'il connait aux alentours du point choisi). Alors, au hasard (puisque le degré de l'exemple précédent n'est que de 6):

addresse = "Boulevard Malesherbes,2,Paris"
lat, lng = gmaps.address_to_latlng(addresse)
print lat, lng
48.8796507 2.3137858
destination = gmaps.latlng_to_address(48.8796507,2.3137858)
print destination
2 Boulevard Malesherbes, 75008 Paris, France

Il permet aussi de réaliser des recherches selon la terminologie Google:

local = gmaps.local_search('cafe near ' + destination)
print local
avec une floppée de résultats...

et la recherche de trajets:

depart = gmaps.latlng_to_address(48.8796507,2.3137858)
destination= gmaps.latlng_to_address(48.8712762,2.3161377)
print destination
2 Rue de Miromesnil, 75008 Paris, France
directions = gmaps.directions(depart, destination)
print directions['Directions']['Distance']['meters']
994
print directions['Directions']['Duration']['seconds']
215
for step in directions['Directions']['Routes'][0]['Steps']:
    print step['descriptionHtml']

Head <b>northeast</b> on <b>Boulevard Malesherbes</b>
Turn <b>right</b> to stay on <b>Boulevard Malesherbes</b>
Slight <b>right</b> at <b>Rue de Miromesnil</b> <div class="google_note">Destination will be on the left</div>
 

Conclusions

Les possibilités sont donc presque infinies.  Rien n'empêche d'ouvrir un fichier de liste d'adresses (formats txt, csv ou même Microsoft@Excel avec l'une des bibliothèques de lecture appropriée),  de passer les adresses à la moulinette avec Python, puis d'enregistrer les résultats dans un autre fichier (voir par exemple canadianamp.ca/2008/12/05/simple-geocoding-with-python-and-urllib/ , www.ninemoreminutes.com/2009/12/google-maps-with-python-and-kml/ , code.google.com/intl/fr/apis/kml/articles/csvtokml.html et beaucoup d'autres).

Ces procédures, intimement liées aux apis des sites de géolocalisation (puisqu'ils ne font que "parser" les réponses envoyées par les serveurs) sont toujours à la merci d'un changement de politique ou de format de la part du site interrogé. Il y a aussi des limites aux demandes que vous pouvez faire (même avec un api). Mais c'est aussi vrai avec toutes les applications de géocodage/géolocalisation, propriétaires ou libres qui utilisent ces services. Les solutions Python permettent donc de sérieuses économies vis-à-vis de l'achat d'un logiciel payant. De plus, le temps de réaction des développeurs Python est très rapide.

Un nouveau module en cours de développement, Pymaps,  permet même d'afficher directement les données géolocalisées sur Google Maps après traitement avec Geopy ou autres.

La démarche suivante serait le changement de projection des résultats obtenus (en WGS84) vers des projections propres à chaque région ou pays. Ce sera le sujet d'un autre article.

Tous les traitements ont été effectués sur Mac OS X avec Python 2.5.4


Site officiel : simplejson
Site officiel : geopy
Site officiel : googlemaps
Site officiel : pymaps

Commentaires

Poster un nouveau commentaire

Le contenu de ce champ sera maintenu privé et ne sera pas affiché publiquement.