Source code for tethne.services.geocode
from geopy import geocoders
import time
import pickle
[docs]class Location(object):
place = ""
latitude = 0.
longitude = 0.
def __init__(self, place="", latitude=0., longitude=0., **kwargs):
self.place = place
self.latitude = latitude
self.longitude = longitude
[docs]class BaseCoder(object):
"""
Base class for geocoders.
"""
persistent = True # Triggers on-disk cacheing with Pickle
sleep_interval = 0.5 # Avoid rate-limiting. Adjust as desired.
def __init__(self, **kwargs):
if self.persistent:
try:
with open(".geocache.pickle", "r") as f:
self.cache = pickle.load(f)
except IOError:
self.cache = {}
def __del__(self):
with open(".geocache.pickle", "w") as f:
pickle.dump(self.cache, f)
[docs] def code_this(self, placename):
"""
Parameters
----------
placename : str or unicode
Returns
-------
location : :class:`.Location`
"""
if type(placename) not in [str, unicode]:
raise ValueError("Encountered non-string in placenames list.")
try: # Check the cache first.
location = self.cache[placename]
except KeyError: # Not in the cache, call the service.
time.sleep(self.sleep_interval) # Avoid rate-limiting.
location = self.get_location(self.code(placename))
self.cache[placename] = location
return location
[docs] def code_list(self, placenames):
"""
Parameters
----------
placenames : list
Returns
-------
locations : dict
Placename - :class:`.Location` mapping.
"""
locations = {}
for name in placenames:
locations[name] = self.code_this(name)
return locations
[docs]class GoogleCoder(BaseCoder):
coder = geocoders.GoogleV3()
code = coder.geocode
[docs] def get_location(self, response):
"""
Parameters
----------
response : tuple
GoogleV3 geocoder response: (u'Name', (Lat, Lon))
Returns
-------
location : :class:`.Location`
"""
if response is None: return None
return Location(place=response[0],
latitude=response[1][0],
longitude=response[1][1])
[docs]class YahooCoder(BaseCoder):
yahoo_base = "http://where.yahooapis.com/v1/places"
lat_searchpath = ".//{http://where.yahooapis.com/v1/schema.rng}centroid/" +\
"{http://where.yahooapis.com/v1/schema.rng}latitude"
lon_searchpath = ".//{http://where.yahooapis.com/v1/schema.rng}centroid/" +\
"{http://where.yahooapis.com/v1/schema.rng}longitude"
name_searchpath = ".//{http://where.yahooapis.com/v1/schema.rng}name"
def __init__(self, yahoo_id, **kwargs):
self.yahoo_id = yahoo_id
super(YahooCoder, self).__init__(self, **kwargs)
[docs] def code(self, name):
"""
Parameters
----------
name : string
Returns
-------
HTTPResponse
"""
import urllib2
rpath = "{0}.q('{1}')?appid={2}".format(self.yahoo_base,
urllib2.quote(name),
self.yahoo_id)
return urllib2.urlopen(rpath).read()
[docs] def get_location(self, response):
"""
Parameters
----------
response : HTTPResponse
Returns
-------
location : :class:`.Location`
"""
import xml.etree.ElementTree as ET
rx = ET.fromstring(response)
try:
lat = float(rx.findall(self.lat_searchpath)[0].text)
lon = float(rx.findall(self.lon_searchpath)[0].text)
place = str(rx.findall(self.name_searchpath)[0].text)
except IndexError:
return None # Nothing found.
return Location(place=place,
latitude=lat,
longitude=lon)