-
Notifications
You must be signed in to change notification settings - Fork 0
/
google_geocoding.py
187 lines (154 loc) · 7.38 KB
/
google_geocoding.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
"""
:class:`.GoogleAPI` geocoder.
:autthor@ksodari
"""
import re
from datetime import timedelta
import requests
from decouple import config
API_KEY = config('GOOGLE_API_KEY')
# Google Maps API URL Format
API_URL = "https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,\
+CA&key=%s" % API_KEY
__all__ = (
"DEFAULT_SCHEME",
"DEFAULT_TIMEOUT",
"DEFAULT_RETRY_TIMEOUT",
)
DEFAULT_SCHEME = 'https'
DEFAULT_TIMEOUT = None
DEFAULT_RETRY_TIMEOUT = 60
DEFAULT_QUERIES_PER_SECOND = 50
class GoogleMapApi():
"""
Geocoder using the Google Maps Locations API. Documentation at:
https://developers.google.com/maps/documentation/geocoding/start
"""
# default api_endpoint
api_url = "https://maps.googleapis.com/maps/api/geocode/json"
api_key = None
structured_query_params = {
'street',
'city',
'state',
'zipCode',
'postalCode',
}
def __init__(self, api_key, client_id=None, client_secret=None,
scheme=DEFAULT_SCHEME, timeout=DEFAULT_TIMEOUT,
retry_timeout=DEFAULT_RETRY_TIMEOUT,
):
"""Initialize a customized Google geocoder with location-specific
address information and your Bing Maps API key.
:param api_key: Maps API key. Required, unless "client_id" and
"client_secret" are set.
:type api_key: string
:param client_id: (for Maps API for Work customers) Your client ID.
:type client_id: string
:param client_secret: (for Maps API for Work customers) Your client
secret (base64 encoded).
:type client_secret: string
:param channel: (for Maps API for Work customers) When set, a channel
parameter with this value will be added to the requests.
This can be used for tracking purpose.
Can only be used with a Maps API client ID.
:type channel: str
:param timeout: Combined connect and read timeout for HTTP requests, in
seconds. Specify "None" for no timeout.
:type timeout: int
"""
if not api_key and not (client_secret and client_id):
raise ValueError("Must provide API key or enterprise credentials "
"when creating client.")
if api_key and not api_key.startswith("AIza"):
raise ValueError("Invalid API key provided.")
"""
if channel:
if not client_id:
raise ValueError("The channel argument must be used with a "
"client ID")
if not re.match("^[a-zA-Z0-9._-]*$", channel):
raise ValueError("The channel argument must be an ASCII "
"alphanumeric string. The period (.), underscore (_)"
"and hyphen (-) characters are allowed.")
"""
# self.session = requests.Session()
# self.channel = channel
# Note: For later use-case
# super(GoogleMapApi, self).__init__(scheme, timeout, retry_timeout, channel=channel)
self.timeout = timeout
self.client_id = client_id
self.client_secret = client_secret
self.api_key = api_key
self.api_url = "{}://maps.googleapis.com/maps/api/geocode/json".format(scheme)
def find_geocode(self, address):
"""
Geocode and address/location
:param address: The address or location query to geocode.
:return: latitude and longitude values
"""
# check if the address is sent as dict format
if isinstance(address, dict):
address = ", ".join(address.values())
# defining a params dict for the parameters to be sent to the API
PARAMS = {
'address': address,
'key': self.api_key,
}
direct_url = "{0}?address={1}&key={2}".format(self.api_url, address, self.api_key)
# response = requests.get(url=self.api_url, params=PARAMS)
# sending get request and saving the response as response object
response = requests.get(url=self.api_url, params=PARAMS)
# extracting data in json format and get the result from json value
data = response.json().get('results')[0]
# extracting latitude, longitude and formatted address
# of the first matching location
latitude = data.get('geometry').get('location').get('lat')
longitude = data.get('geometry').get('location').get('lng')
formatted_address = data.get('formatted_address')
postal_code = data.get('address_components')[-1].get('short_name')
# context to return
context = {'lat': latitude, 'lng': longitude, 'postalCode': postal_code, 'address': formatted_address}
# printing the output
print("Latitude: {}\nLongitude: {}\nFormatted Address: {}".format(latitude, longitude, formatted_address))
return data or context
def reverse_geocode(self, latlng):
# if latlng is sent as list item
if isinstance(latlng, list):
if latlng.__len__() != 2:
raise ValueError("Invalid latlng values. The list must be of length 2 with latitude and longitude "
"values only.")
latlng = "{}, {}".format(latlng[0], latlng[1])
# if latlng is a dictionary formatted data
if isinstance(latlng, dict):
if not ({'latitude', 'longitude', 'lat', 'lng'} >= latlng.keys()):
raise ValueError("Invalid format. The dict must be of length 2 with key as 'latitude' or 'lat' and "
"'longitude' or 'lng' only.")
latlng = "{}, {}".format(latlng.get('lat', latlng.get('latitude')), latlng.get('lng', latlng.get(
'longitude')))
# check if latlng is a tuple formatted data
if isinstance(latlng, tuple):
if latlng.__len__() != 2:
raise ValueError("Invalid latlng values. The tuple must be of length 2 with latitude and longitude "
"values only formatted as (lat, lng).")
latlng = "{}, {}".format(latlng[0], latlng[1])
# defining a params dict for the parameters to be sent to the API URL
PARAMS = {
'latlng': latlng,
'key': self.api_key,
}
# sample_url = https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&key=YOUR_API_KEY
# sending get request and saving the response as response object
response = requests.get(url=self.api_url, params=PARAMS)
# extracting data in json format and get the result from json value
data = response.json().get('results')[0]
# extracting latitude, longitude and formatted address of the first matching location
latitude = data.get('geometry').get('location').get('lat')
longitude = data.get('geometry').get('location').get('lng')
formatted_address = data.get('formatted_address')
postal_code = data.get('address_components')[-1].get('short_name')
# printing the output
print("Latitude: {}\nLongitude: {}\nFormatted Address: {}".format(latitude, longitude, formatted_address))
# context to return
context = {'lat': latitude, 'lng': longitude, 'postalCode': postal_code, 'address': formatted_address}
return data