lab_weather/geocoder/google_places.py

182 lines
6.0 KiB
Python

#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import google_key
from geocoder.location import BBox
# todo: Paging (pagetoken) is not fully supported since we only return the first result. Need to return all results to the user so paging will make sense
# todo: Add support for missing results fields html_attributions, opening_hours, photos, scope, alt_ids, types [not just the first one]
# todo: Add support for nearbysearch and radarsearch variations of the Google Places API
class PlacesResult(OneResult):
def __init__(self, json_content):
# flatten geometry
geometry = json_content.get('geometry', {})
self._location = geometry.get('location', {})
json_content['northeast'] = geometry.get(
'viewport', {}).get('northeast', {})
json_content['southwest'] = geometry.get(
'viewport', {}).get('southwest', {})
# proceed with super.__init__
super(PlacesResult, self).__init__(json_content)
@property
def lat(self):
return self._location.get('lat')
@property
def lng(self):
return self._location.get('lng')
@property
def id(self):
return self.raw.get('id')
@property
def reference(self):
return self.raw.get('reference')
@property
def place_id(self):
return self.raw.get('place_id')
@property
def type(self):
type = self.raw.get('types')
if type:
return type[0]
@property
def address(self):
return self.raw.get('formatted_address')
@property
def icon(self):
return self.raw.get('icon')
@property
def name(self):
return self.raw.get('name')
@property
def vicinity(self):
return self.raw.get('vicinity')
@property
def price_level(self):
return self.raw.get('price_level')
@property
def rating(self):
return self.raw.get('rating')
class PlacesQuery(MultipleResultsQuery):
"""
Google Places API
====================
The Google Places API Web Service allows you to query for place information on a variety of categories,
such as: establishments, prominent points of interest, geographic locations, and more.
You can search for places either by proximity or a text string.
A Place Search returns a list of places along with summary information about each place; additional
information is available via a Place Details query.
At this time, only the "Text Search" is supported by this library. "Text Search" can be used
when you don't have pristine formatted addresses required by the regular Google Maps Geocoding API
or when you want to do 'nearby' searches like 'restaurants near Sydney'.
The Geocoding best practices reference indicates that when you have 'ambiguous queries in an automated system
you would be better served using the Places API Text Search than the Maps Geocoding API
https://developers.google.com/maps/documentation/geocoding/best-practices
API Reference
-------------
https://developers.google.com/places/web-service/intro
https://developers.google.com/places/web-service/search
l = geocoder.google('Elm Plaza Shopping Center, Enfield, CT 06082', method='places')
l = geocoder.google('food near white house', method='places')
l = geocoder.google('1st and main', method='places')
Parameters
----------
:param location: Your search location or phrase you want geocoded.
:param key: Your Google developers free key.
:param proximity: (optional) lat,lng point around which results will be given preference
:param radius: (optional) in meters, used with proximity
:param language: (optional) 2-letter code of preferred language of returned address elements.
:param minprice: (optional) 0 (most affordable) to 4 (most expensive)
:param maxprice: (optional) 0 (most affordable) to 4 (most expensive)
:param opennow: (optional) value is ignored. when present, closed places and places without opening hours will be omitted
:param pagetoken: (optional) get next 20 results from previously run search. when set, other criteria are ignored
:param type: (optional) restrict results to one type of place
"""
provider = 'google'
method = 'places'
_URL = 'https://maps.googleapis.com/maps/api/place/textsearch/json'
_RESULT_CLASS = PlacesResult
_KEY = google_key
def __init__(self, location, **kwargs):
super(PlacesQuery, self).__init__(location, **kwargs)
self.next_page_token = None
def _build_params(self, location, provider_key, **kwargs):
# handle specific case of proximity (aka 'location' for google)
bbox = kwargs.get('proximity', '')
if bbox:
bbox = BBox.factory(bbox)
# do not forget to convert bbox to google expectations...
bbox = bbox.latlng
# define all
params = {
# required
'query': location,
'key': provider_key,
# optional
'location': bbox,
'radius': kwargs.get('radius', ''),
'language': kwargs.get('language', ''),
'minprice': kwargs.get('minprice', ''),
'maxprice': kwargs.get('maxprice', ''),
'type': kwargs.get('type', ''),
}
# optional, don't send unless needed
if 'opennow' in kwargs:
params['opennow'] = ''
# optional, don't send unless needed
if 'pagetoken' in kwargs:
params['pagetoken'] = kwargs['pagetoken']
return params
def _parse_results(self, json_response):
super(PlacesQuery, self)._parse_results(json_response)
# store page token if any
self.next_page_token = json_response.get('next_page_token')
def _adapt_results(self, json_response):
return json_response['results']
@property
def query(self):
return self.location
if __name__ == '__main__':
g = PlacesQuery('rail station, Ottawa')
g.debug()