Python Geocoding Tutorial

This is a tutorial for using the OpenCage geocoding API in Python.

Topics covered in this tutorial

Background

The code examples below will use your geocoding API key once you log in.

Before we dive in to the tutorial

  1. Sign up for an OpenCage geocoding API key.
  2. Play with the demo page, so that you see the actual response the API returns.
  3. Browse the API reference, so you understand the optional parameters, best practices, possible response codes, and the rate limiting on free trial accounts.

Video Tutorials

If you prefer video, over on YouTube we have two 10 minute tutorial videos showing how to geocode using Python, one tutorial video focused on reverse geocoding, the other explaining forward geocoding.

Install the OpenCage Python module

Compatible with Python version 3.8 and newer.

pip3 install opencage

Convert coordinates to location (reverse geocoding)

from opencage.geocoder import OpenCageGeocode
from pprint import pprint

key = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(key)

results = geocoder.reverse_geocode(44.8303087, -0.5761911)
pprint(results)
# [{'components': {'ISO_3166-1_alpha-2': 'FR',
#                  'ISO_3166-1_alpha-3': 'FRA',
#                  'ISO_3166-2': ['FR-NAQ', 'FR-33'],
#                  '_category': 'building',
#                  '_type': 'building',
#                  'city': 'Bordeaux',
#                  'continent': 'Europe',
#                  'country': 'France',
#                  'country_code': 'fr',
#                  'county': 'Gironde',
#                  'house_number': '11',
#                  'municipality': 'Bordeaux',
#                  'political_union': 'European Union',
#                  'postcode': '33000',
#                  'region': 'Metropolitan France',
#                  'road': 'Rue Sauteyron',
#                  'state': 'New Aquitaine',
#                  'state_code': 'NAQ',
#                  'suburb': 'Victoire'},
#   'confidence': 10,
#   'formatted': '11 Rue Sauteyron, 33800 Bordeaux, France',
#   'geometry': {'lat': 44.8303087, 'lng': -0.5761911}}]

Set output language, error handling

from opencage.geocoder import OpenCageGeocode
from opencage.geocoder import InvalidInputError, RateLimitExceededError, UnknownError

key = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(key)

try:
  results = geocoder.reverse_geocode(44.8303087, -0.5761911, language='de', no_annotations='1')
  if results and len(results):
    print(results[0]['formatted'])
    # 11 Rue Sauteyron, 33800 Bordeaux, Frankreich
except RateLimitExceededError as ex:
  print(ex)
  # You have used the requests available on your plan.
except InvalidInputError as ex:
  # this happens for example with invalid unicode in the input data

Lookup coordinates from address (forward geocoding)

from opencage.geocoder import OpenCageGeocode

key = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(key)

query = u'Bosutska ulica 10, Trnje, Zagreb, Croatia'

# no need to URI encode query, module does that for you
results = geocoder.geocode(query)

print(u'%f;%f;%s;%s' % (results[0]['geometry']['lat'],
                        results[0]['geometry']['lng'],
                        results[0]['components']['country_code'],
                        results[0]['annotations']['timezone']['name']))
# 45.797095;15.982453;hr;Europe/Belgrade

Batch geocode a file of addresses

Create a file containing addresses
Madrid, Spain
Milan, Italy
Berlin, Germany
München, Deutschland
Philipsbornstr 2, 30165 Hannover, Germany
import sys
from opencage.geocoder import OpenCageGeocode

key = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(key)
addressfile = 'addresses.txt'

try:
  with open(addressfile,'r') as f:
    for line in f:
      address = line.strip()

      # no need to URI encode query, module does that for you
      results = geocoder.geocode(address, no_annotations='1')

      if results and len(results):
        longitude = results[0]['geometry']['lng']
        latitude  = results[0]['geometry']['lat']
        print(u'%f;%f;%s' % (latitude, longitude, address))
        # 40.416705;-3.703582;Madrid, Spain
        # 45.466797;9.190498;Milan, Italy
        # 52.517037;13.388860;Berlin, Germany
        # 48.1371079;11.5753822;München, Deutschland
        # 52.3878553;9.7332249;Philipsbornstr 2, 30165 Hannover, Germany
      else:
        sys.stderr.write("not found: %s\n" % address)
except IOError:
  print('Error: File %s does not appear to exist.' % addressfile)
except RateLimitExceededError as ex:
  print(ex)
  # You have used the requests available on your plan.

Running many parallel queries

By default the Python Request HTTP library will only run one HTTP request, even if you wrap the logic inside multipthreading or asynchronous calls. At low level it will block other HTTP requests.

Instead you should use the asyncio library for HTTP requests. We prepared a more complex code example of python parallel batch requests using a queue and task workers. We've used variations of the script for lists of 10s of millions of addresses.

Our Python module comes with a command line interface (CLI) tool, see our full geocoding CLI tutorial.

Commandline example of using batch.py

Before you start geocoding at high volume, please read our guide to geocoding large datasets where we explain various strategies and points to consider.

SSL work-around

If you have trouble accessing the OpenCage API with https, e.g. issues with OpenSSL libraries in your environment, then you can set the 'http' protocol instead. Please understand that the connection to the OpenCage API will no longer be encrypted.
from opencage.geocoder import OpenCageGeocode

key = 'YOUR-API-KEY'
geocoder = OpenCageGeocode(key, 'http')

Alternative Python modules

Start your free trial

2,500 geocoding API requests per day.

No credit card required.