Geocoding using the Open Street Map API

Here we explore an example of using an Application Programming Interface, or API. Briefly, an API is a set of commands we can send over the internet to a remote server, spurring the server to process these commands and return a response. In this example, we'll explore how we can use the Open Street Map's geocoding API to get the coordinates responding to a particular address.

This is not an in-depth exploration of this particular API, but rather an introduction on how to use an API within Python, specfically using the handy requests and json libraries.


First we import the requests and json modules.
Usfeful documentation on these modules are found here:


In [2]:
#Import modules
import requests
import json

Now we will form the request to invoke the Open Street Map API. Documentation on this API is found here: http://wiki.openstreetmap.org/wiki/Nominatim

First, we'll generate an example address to geocode. Why not use Environment Hall? But feel free to use your own address!


In [3]:
#Get the address
address = '9 Circuit Drive, Durham, NC, 27708'

An API request consists two components: the service endpoint and a set of parameters associated with the service.

When using the requests module to create and send our request, we supply the service endpoint is a string containing the server address (as a URL) and the service name (here, it's search). And the parameters are supplied in the form of a Python dictionary. Here, the two paramters we'll pass are the format and address parameters.


In [4]:
#Form the request
osmURL = 'http://nominatim.openstreetmap.org/search'
params = {'format':'json','q':address}

Now, we can use requests to send our command off to the OSM server. The server's response is saved as the response variable.


In [5]:
#Send the request
response = requests.get(osmURL, params)

The response object below contains a lot of information. You are encouraged to explore this object further. Here we'll explore one property which is the full URL created. Copy and paste the result in your favorite browser, and you'll see the result of our request in raw form. When you try this, try changing 'json' to 'html' in the URL...


In [9]:
response.url


Out[9]:
u'http://nominatim.openstreetmap.org/search?q=9+Circuit+Drive%2C+Durham%2C+NC%2C+27708&format=json'

In [12]:
#Opens the URL as an html response (vs JSON) in a web browser...
import webbrowser
webbrowser.open_new(response.url.replace('json','html'))


Out[12]:
True

What we really want from the response, however, is the data returned by the service. The json function of the response object converts the response to an object in JavaScript Object Notation, or JSON. JSON is esentially a list of dictionaries that we can easily manipulate in Python.


In [33]:
#Read in the response as a JSON encoded object
jsonObj = response.json()

pprint or "pretty print" allows us to display JSON objects in a readable format. Let's make a pretty print of our JSON repsonse.


In [34]:
from pprint import pprint
pprint(jsonObj)


[{u'boundingbox': [u'36.0052912',
                   u'36.0061023',
                   u'-78.9434647',
                   u'-78.9409989'],
  u'class': u'highway',
  u'display_name': u'Circuit Drive, Crest Street, Durham, Durham County, North Carolina, 27705, United States of America',
  u'importance': 0.335,
  u'lat': u'36.0055806',
  u'licence': u'Data \xa9 OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright',
  u'lon': u'-78.942014',
  u'osm_id': u'16544972',
  u'osm_type': u'way',
  u'place_id': u'71321894',
  u'type': u'unclassified'}]

Our response contains only one item in the JSON list. We'll extract to a dictionary and print it's items.


In [36]:
dataDict = jsonObj[0]
print dataDict.keys()


[u'display_name', u'importance', u'place_id', u'lon', u'lat', u'osm_type', u'licence', u'osm_id', u'boundingbox', u'type', u'class']

Now we can easily grab the lat and lon objects from our response


In [38]:
lat = float(dataDict['lat'])
lng = float(dataDict['lon'])
print "The lat,lng


36.0055806 -78.942014

In [37]:
d = jsonObj[0]
d['lon'],d['lat']


Out[37]:
(u'-78.942014', u'36.0055806')

Now let's inform the user of the result of the whole process...


In [41]:
print "The address {0} is located at\n{1}° Lat, {2}° Lon".format(address,lat,lng)


The address 9 Circuit Drive, Durham, NC, 27708 is located at
36.0055806° Lat, -78.942014° Lon