This repository has been archived by the owner on May 8, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
geocoder.py
156 lines (120 loc) · 5.31 KB
/
geocoder.py
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Simple geocoder for mappie
This is just a simple 'wrapper' around the `geopy` `GoogleV3` geocoder. This
version allows for more control over which components of the returned JSON
feed are available to the user.
"""
from geopy.geocoders import GoogleV3
import geopy.util as util
from urllib import urlencode
from urllib2 import urlopen
# so that we have access to geopy directly if we want it
import geopy as geopy
try:
import json
except ImportError:
try:
import simplejson as json
except ImportError:
from django.utils import simplejson as json
class Geocoder(GoogleV3):
'''Geocoder using the Google Maps v3 API.
This is just a simple 'wrapper' around the `geopy` `GoogleV3` geocoder,
that allows for more control over which components of the geocoded
results are returned.
'''
def geocode_url(self, url, exactly_one=True, output='latlon'):
'''Fetches the url and returns the result.
'''
util.logger.debug("Fetching %s..." % url)
page = urlopen(url)
return self.parse_json(page, exactly_one, output)
def geocode(self, string, bounds=None, region=None, language=None,
sensor=False, exactly_one=True, output='latlon'):
'''Geocode an address.
string : str (required)
The address that you want to geocode.
bounds : tuple (optional)
The bounding box of the viewport within which to bias geocode
results more prominently.
region : str (optional)
The region code, specified as a ccTLD ("top-level domain")
two-character value.
language : str (optional)
The language in which to return results. See the supported list
of domain languages. Note that we often update supported languages
so this list may not be exhaustive. If language is not supplied,
the geocoder will attempt to use the native language of the domain
from which the request is sent wherever possible.
sensor : bool (required)
Indicates whether or not the geocoding request comes from a device
with a location sensor. This value must be either True or False.
output : str (optional)
The type of output to return. Can be one of the following:
'latlon' - (lat, lon) tuple
'alatlon' - address, (lat, lon) tuple
'bbox' - bounding box tuple (ymin, ymax, xmin, xmax)
'geometry' - geometry component of returned JSON as Python dict
'all' - entire returned JSON data as Python dict
'''
if isinstance(string, unicode):
string = string.encode('utf-8')
params = {
'address': self.format_string % string,
'sensor': str(sensor).lower()
}
if bounds:
params['bounds'] = bounds
if region:
params['region'] = region
if language:
params['language'] = language
if not self.premier:
url = self.get_url(params)
else:
url = self.get_signed_url(params)
return self.geocode_url(url, exactly_one, output)
def parse_json(self, page, exactly_one=True, output='latlon'):
'''Parse returned json feed of geocoded results
Returns various forms of the geocoded 'location' from the JSON feed.
Type of locations include latitude and longitude, address, bounding
box (viewport), geometry information, or the entire JSON feed.
'''
if not isinstance(page, basestring):
page = util.decode_page(page)
self.doc = json.loads(page)
places = self.doc.get('results', [])
if not places:
check_status(self.doc.get('status'))
return None
elif exactly_one and len(places) != 1:
raise ValueError(
"Didn't find exactly one placemark! (Found %d)" % len(places))
outputs = ('latlon', 'alatlon', 'bbox', 'geometry', 'all')
if not output in outputs:
raise ValueError(
"Invalid `output` parameter, must be one of ('%s')" % "', '".join(outputs))
def parse_place(place):
'''Get the location, lat, lng from a single json place.'''
location = place.get('formatted_address')
latitude = place['geometry']['location']['lat']
longitude = place['geometry']['location']['lng']
if output == 'alatlon':
return (location, (latitude, longitude))
elif output == 'bbox':
northeast = place['geometry']['viewport']['northeast']
southwest = place['geometry']['viewport']['southwest']
xmin, xmax = southwest['lng'], northeast['lng']
ymin, ymax = southwest['lat'], northeast['lat']
return (ymin, ymax, xmin, xmax)
elif output == 'geometry':
return place['geometry']
elif output == 'all':
return place
else: # latlon
return (latitude, longitude)
if exactly_one:
return parse_place(places[0])
else:
return [parse_place(place) for place in places]