I was just checking that everything was submitted but I guess this wasn't.

This commit is contained in:
root 2024-12-16 23:58:51 -05:00
parent 2313bcfbff
commit 66f67710f0
136 changed files with 8869 additions and 2 deletions

46
__init__.py Normal file
View File

@ -0,0 +1,46 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
"""
Geocoder
~~~~~~~~
Simple and consistent geocoding library written in Python.
Many online providers such as Google & Bing have geocoding services,
these providers do not include Python libraries and have different
JSON responses between each other.
Consistant JSON responses from various providers.
>>> g = geocoder.google('New York City')
>>> g.latlng
[40.7127837, -74.0059413]
>>> g.state
'New York'
>>> g.json
...
"""
__title__ = 'geocoder'
__author__ = 'Denis Carriere'
__author_email__ = 'carriere.denis@gmail.com'
__version__ = '1.38.1'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2013-2016 Denis Carriere'
# CORE
from geocoder.api import get, yahoo, bing, geonames, mapquest, google, mapbox # noqa
from geocoder.api import nokia, osm, tomtom, geolytica, arcgis, opencage, locationiq # noqa
from geocoder.api import maxmind, ipinfo, freegeoip, ottawa, here, baidu, gaode, w3w # noqa
from geocoder.api import yandex, mapzen, komoot, tamu, geocodefarm, tgos, uscensus # noqa
from geocoder.api import gisgraphy # noqa
# EXTRAS
from geocoder.api import timezone, elevation, places, ip, canadapost, reverse, distance, location # noqa
# CLI
from geocoder.cli import cli # noqa

View File

46
geocoder/__init__.py Normal file
View File

@ -0,0 +1,46 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
"""
Geocoder
~~~~~~~~
Simple and consistent geocoding library written in Python.
Many online providers such as Google & Bing have geocoding services,
these providers do not include Python libraries and have different
JSON responses between each other.
Consistant JSON responses from various providers.
>>> g = geocoder.google('New York City')
>>> g.latlng
[40.7127837, -74.0059413]
>>> g.state
'New York'
>>> g.json
...
"""
__title__ = 'geocoder'
__author__ = 'Denis Carriere'
__author_email__ = 'carriere.denis@gmail.com'
__version__ = '1.38.1'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2013-2016 Denis Carriere'
# CORE
from geocoder.api import get, yahoo, bing, geonames, mapquest, google, mapbox # noqa
from geocoder.api import nokia, osm, tomtom, geolytica, arcgis, opencage, locationiq # noqa
from geocoder.api import maxmind, ipinfo, freegeoip, ottawa, here, baidu, gaode, w3w # noqa
from geocoder.api import yandex, mapzen, komoot, tamu, geocodefarm, tgos, uscensus # noqa
from geocoder.api import gisgraphy # noqa
# EXTRAS
from geocoder.api import timezone, elevation, places, ip, canadapost, reverse, distance, location # noqa
# CLI
from geocoder.cli import cli # noqa

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

661
geocoder/api.py Normal file
View File

@ -0,0 +1,661 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.distance import Distance
from geocoder.location import Location
from geocoder.arcgis import ArcgisQuery
from geocoder.baidu import BaiduQuery
from geocoder.bing import BingQuery, BingQueryDetail
from geocoder.canadapost import CanadapostQuery
from geocoder.freegeoip import FreeGeoIPQuery
from geocoder.gaode import GaodeQuery
from geocoder.geocodefarm import GeocodeFarmQuery
from geocoder.geolytica import GeolyticaQuery
from geocoder.gisgraphy import GisgraphyQuery
from geocoder.here import HereQuery
from geocoder.ipinfo import IpinfoQuery
from geocoder.komoot import KomootQuery
from geocoder.locationiq import LocationIQQuery
from geocoder.mapbox import MapboxQuery
from geocoder.mapquest import MapquestQuery
from geocoder.mapzen import MapzenQuery
from geocoder.maxmind import MaxmindQuery
from geocoder.opencage import OpenCageQuery
from geocoder.osm import OsmQuery, OsmQueryDetail
from geocoder.ottawa import OttawaQuery
from geocoder.tamu import TamuQuery
from geocoder.tomtom import TomtomQuery
from geocoder.tgos import TgosQuery
from geocoder.uscensus import USCensusQuery
from geocoder.yahoo import YahooQuery
from geocoder.yandex import YandexQuery
from geocoder.w3w import W3WQuery
from geocoder.arcgis_reverse import ArcgisReverse
from geocoder.baidu_reverse import BaiduReverse
from geocoder.bing_reverse import BingReverse
from geocoder.gaode_reverse import GaodeReverse
from geocoder.geocodefarm_reverse import GeocodeFarmReverse
from geocoder.gisgraphy_reverse import GisgraphyReverse
from geocoder.here_reverse import HereReverse
from geocoder.locationiq_reverse import LocationIQReverse
from geocoder.komoot_reverse import KomootReverse
from geocoder.mapbox_reverse import MapboxReverse
from geocoder.mapquest_reverse import MapquestReverse
from geocoder.mapzen_reverse import MapzenReverse
from geocoder.opencage_reverse import OpenCageReverse
from geocoder.osm_reverse import OsmReverse
from geocoder.uscensus_reverse import USCensusReverse
from geocoder.w3w_reverse import W3WReverse
from geocoder.yandex_reverse import YandexReverse
from geocoder.mapquest_batch import MapquestBatch
from geocoder.bing_batch_forward import BingBatchForward
from geocoder.bing_batch_reverse import BingBatchReverse
from geocoder.uscensus_batch import USCensusBatch
# Geonames Services
from geocoder.geonames import GeonamesQuery
from geocoder.geonames_details import GeonamesDetails
from geocoder.geonames_children import GeonamesChildren
from geocoder.geonames_hierarchy import GeonamesHierarchy
# Google Services
from geocoder.google import GoogleQuery
from geocoder.google_timezone import TimezoneQuery
from geocoder.google_reverse import GoogleReverse
from geocoder.google_elevation import ElevationQuery
from geocoder.google_places import PlacesQuery
options = {
'osm': {
'geocode': OsmQuery,
'details': OsmQueryDetail,
'reverse': OsmReverse,
},
'tgos': {
'geocode': TgosQuery
},
'here': {
'geocode': HereQuery,
'reverse': HereReverse,
},
'baidu': {
'geocode': BaiduQuery,
'reverse': BaiduReverse
},
'gaode': {
'geocode': GaodeQuery,
'reverse': GaodeReverse
},
'yahoo': {'geocode': YahooQuery},
'tomtom': {'geocode': TomtomQuery},
'arcgis': {
'geocode': ArcgisQuery,
'reverse': ArcgisReverse
},
'ottawa': {'geocode': OttawaQuery},
'mapbox': {
'geocode': MapboxQuery,
'reverse': MapboxReverse,
},
'maxmind': {'geocode': MaxmindQuery},
'ipinfo': {'geocode': IpinfoQuery},
'geonames': {
'geocode': GeonamesQuery,
'details': GeonamesDetails,
'timezone': GeonamesDetails,
'children': GeonamesChildren,
'hierarchy': GeonamesHierarchy
},
'freegeoip': {'geocode': FreeGeoIPQuery},
'w3w': {
'geocode': W3WQuery,
'reverse': W3WReverse,
},
'yandex': {
'geocode': YandexQuery,
'reverse': YandexReverse
},
'mapquest': {
'geocode': MapquestQuery,
'reverse': MapquestReverse,
'batch': MapquestBatch
},
'geolytica': {'geocode': GeolyticaQuery},
'canadapost': {'geocode': CanadapostQuery},
'opencage': {
'geocode': OpenCageQuery,
'reverse': OpenCageReverse,
},
'bing': {
'geocode': BingQuery,
'details': BingQueryDetail,
'reverse': BingReverse,
'batch': BingBatchForward,
'batch_reverse': BingBatchReverse
},
'google': {
'geocode': GoogleQuery,
'reverse': GoogleReverse,
'timezone': TimezoneQuery,
'elevation': ElevationQuery,
'places': PlacesQuery,
},
'mapzen': {
'geocode': MapzenQuery,
'reverse': MapzenReverse,
},
'komoot': {
'geocode': KomootQuery,
'reverse': KomootReverse,
},
'tamu': {
'geocode': TamuQuery
},
'geocodefarm': {
'geocode': GeocodeFarmQuery,
'reverse': GeocodeFarmReverse,
},
'uscensus': {
'geocode': USCensusQuery,
'reverse': USCensusReverse,
'batch': USCensusBatch
},
'locationiq': {
'geocode': LocationIQQuery,
'reverse': LocationIQReverse,
},
'gisgraphy': {
'geocode': GisgraphyQuery,
'reverse': GisgraphyReverse,
},
}
def get(location, **kwargs):
"""Get Geocode
:param ``location``: Your search location you want geocoded.
:param ``provider``: The geocoding engine you want to use.
:param ``method``: Define the method (geocode, method).
"""
provider = kwargs.get('provider', 'bing').lower().strip()
method = kwargs.get('method', 'geocode').lower().strip()
if isinstance(location, (list, dict)) and method == 'geocode':
raise ValueError("Location should be a string")
if provider not in options:
raise ValueError("Invalid provider")
else:
if method not in options[provider]:
raise ValueError("Invalid method")
return options[provider][method](location, **kwargs)
def distance(*args, **kwargs):
"""Distance tool measures the distance between two or multiple points.
:param ``location``: (min 2x locations) Your search location you want geocoded.
:param ``units``: (default=kilometers) Unit of measurement.
> kilometers
> miles
> feet
> meters
"""
return Distance(*args, **kwargs)
def location(location, **kwargs):
"""Parser for different location formats
"""
return Location(location, **kwargs)
def google(location, **kwargs):
"""Google Provider
:param ``location``: Your search location you want geocoded.
:param ``method``: (default=geocode) Use the following:
> geocode
> places
> reverse
> batch
> timezone
> elevation
"""
return get(location, provider='google', **kwargs)
def mapbox(location, **kwargs):
"""Mapbox Provider
:param ``location``: Your search location you want geocoded.
:param ``proximity``: Search nearby [lat, lng]
:param ``method``: (default=geocode) Use the following:
> geocode
> reverse
> batch
"""
return get(location, provider='mapbox', **kwargs)
def yandex(location, **kwargs):
"""Yandex Provider
:param ``location``: Your search location you want geocoded.
:param ``maxRows``: (default=1) Max number of results to fetch
:param ``lang``: Chose the following language:
> ru-RU Russian (by default)
> uk-UA Ukrainian
> be-BY Belarusian
> en-US American English
> en-BR British English
> tr-TR Turkish (only for maps of Turkey)
:param ``kind``: Type of toponym (only for reverse geocoding):
> house - house or building
> street - street
> metro - subway station
> district - city district
> locality - locality (city, town, village, etc.)
"""
return get(location, provider='yandex', **kwargs)
def w3w(location, **kwargs):
"""what3words Provider
:param ``location``: Your search location you want geocoded.
:param ``key``: W3W API key.
:param ``method``: Chose a method (geocode, method)
"""
return get(location, provider='w3w', **kwargs)
def baidu(location, **kwargs):
"""Baidu Provider
:param ``location``: Your search location you want geocoded.
:param ``key``: Baidu API key.
:param ``referer``: Baidu API referer website.
"""
return get(location, provider='baidu', **kwargs)
def gaode(location, **kwargs):
"""Gaode Provider
:param ``location``: Your search location you want geocoded.
:param ``key``: Gaode API key.
:param ``referer``: Gaode API referer website.
"""
return get(location, provider='gaode', **kwargs)
def komoot(location, **kwargs):
"""Ottawa Provider
:param ``location``: Your search location you want geocoded.
"""
return get(location, provider='komoot', **kwargs)
def ottawa(location, **kwargs):
"""Ottawa Provider
:param ``location``: Your search location you want geocoded.
:param ``maxRows``: (default=1) Max number of results to fetch
"""
return get(location, provider='ottawa', **kwargs)
def elevation(location, **kwargs):
"""Elevation - Google Provider
:param ``location``: Your search location you want to retrieve elevation data.
"""
return get(location, method='elevation', provider='google', **kwargs)
def places(location, **kwargs):
"""Places - Google Provider
:param ``location``: Your search location you want geocoded.
:param ``proximity``: Search within given area (bbox, bounds, or around latlng)
"""
return get(location, method='places', provider='google', **kwargs)
def timezone(location, **kwargs):
"""Timezone - Google Provider
:param ``location``: Your search location you want to retrieve timezone data.
:param ``timestamp``: Define your own specified time to calculate timezone.
"""
return get(location, method='timezone', provider='google', **kwargs)
def reverse(location, provider="google", **kwargs):
"""Reverse Geocoding
:param ``location``: Your search location you want to reverse geocode.
:param ``key``: (optional) use your own API Key from Bing.
:param ``provider``: (default=google) Use the following:
> google
> bing
"""
return get(location, method='reverse', provider=provider, **kwargs)
def bing(location, **kwargs):
"""Bing Provider
:param ``location``: Your search location you want geocoded.
:param ``key``: (optional) use your own API Key from Bing.
:param ``maxRows``: (default=1) Max number of results to fetch
:param ``method``: (default=geocode) Use the following:
> geocode
> reverse
"""
return get(location, provider='bing', **kwargs)
def yahoo(location, **kwargs):
"""Yahoo Provider
:param ``location``: Your search location you want geocoded.
"""
return get(location, provider='yahoo', **kwargs)
def geolytica(location, **kwargs):
"""Geolytica (Geocoder.ca) Provider
:param ``location``: Your search location you want geocoded.
"""
return get(location, provider='geolytica', **kwargs)
def opencage(location, **kwargs):
"""Opencage Provider
:param ``location``: Your search location you want geocoded.
:param ``key``: (optional) use your own API Key from OpenCage.
"""
return get(location, provider='opencage', **kwargs)
def arcgis(location, **kwargs):
"""ArcGIS Provider
:param ``location``: Your search location you want geocoded.
"""
return get(location, provider='arcgis', **kwargs)
def here(location, **kwargs):
"""HERE Provider
:param ``location``: Your search location you want geocoded.
:param ``app_code``: (optional) use your own Application Code from HERE.
:param ``app_id``: (optional) use your own Application ID from HERE.
:param ``maxRows``: (default=1) Max number of results to fetch
:param ``method``: (default=geocode) Use the following:
> geocode
> reverse
"""
return get(location, provider='here', **kwargs)
def nokia(location, **kwargs):
"""HERE Provider
:param ``location``: Your search location you want geocoded.
:param ``app_code``: (optional) use your own Application Code from HERE.
:param ``app_id``: (optional) use your own Application ID from HERE.
:param ``method``: (default=geocode) Use the following:
> geocode
> reverse
"""
return get(location, provider='here', **kwargs)
def tomtom(location, **kwargs):
"""TomTom Provider
:param ``location``: Your search location you want geocoded.
:param ``key``: (optional) use your own API Key from TomTom.
:param ``maxRows``: (default=1) Max number of results to fetch
"""
return get(location, provider='tomtom', **kwargs)
def mapquest(location, **kwargs):
"""MapQuest Provider
:param ``location``: Your search location you want geocoded.
:param ``key``: (optional) use your own API Key from MapQuest.
:param ``maxRows``: (default=1) Max number of results to fetch
:param ``method``: (default=geocode) Use the following:
> geocode
> reverse
"""
return get(location, provider='mapquest', **kwargs)
def osm(location, **kwargs):
"""OSM Provider
:param ``location``: Your search location you want geocoded.
:param ``url``: Custom OSM Server URL location
(ex: http://nominatim.openstreetmap.org/search)
"""
return get(location, provider='osm', **kwargs)
def maxmind(location='me', **kwargs):
"""MaxMind Provider
:param ``location``: Your search IP Address you want geocoded.
:param ``location``: (optional) if left blank will return your
current IP address's location.
"""
return get(location, provider='maxmind', **kwargs)
def ipinfo(location='', **kwargs):
"""IP Info.io Provider
:param ``location``: Your search IP Address you want geocoded.
:param ``location``: (optional) if left blank will return your
current IP address's location.
"""
return get(location, provider='ipinfo', **kwargs)
def freegeoip(location, **kwargs):
"""FreeGeoIP Provider
:param ``location``: Your search IP Address you want geocoded.
:param ``location``: (optional) if left blank will return your
current IP address's location.
"""
return get(location, provider='freegeoip', **kwargs)
def ip(location, **kwargs):
"""IP Address lookup
:param ``location``: Your search IP Address you want geocoded.
:param ``location``: (optional) if left blank will return your
current IP address's location.
"""
return get(location, provider='ipinfo', **kwargs)
def canadapost(location, **kwargs):
"""CanadaPost Provider
:param ``location``: Your search location you want geocoded.
:param ``key``: (optional) API Key from CanadaPost Address Complete.
:param ``language``: (default=en) Output language preference.
:param ``country``: (default=ca) Geofenced query by country.
:param ``maxRows``: (default=1) Max number of results to fetch
"""
return get(location, provider='canadapost', **kwargs)
def postal(location, **kwargs):
"""CanadaPost Provider
:param ``location``: Your search location you want geocoded.
:param ``key``: (optional) use your own API Key from
CanadaPost Address Complete.
"""
return get(location, provider='canadapost', **kwargs)
def geonames(location, **kwargs):
"""GeoNames Provider
:param ``location``: Your search location you want geocoded.
:param ``geonameid``: The place you want children / hierarchy for.
:param ``key``: (required) geonames *username*: needs to be passed with each request.
:param ``maxRows``: (default=1) Max number of results to fetch
:param ``proximity``: Search within given area (bbox, bounds, or around latlng)
:param ``method``: (default=geocode) Use the following:
> geocode
> details (mainly for administrive data and timezone)
> timezone (alias for details)
> children
> hierarchy
"""
return get(location, provider='geonames', **kwargs)
def mapzen(location, **kwargs):
"""Mapzen Provider
:param ``location``: Your search location you want geocoded.
:param ``maxRows``: (default=1) Max number of results to fetch
"""
return get(location, provider='mapzen', **kwargs)
def tamu(location, **kwargs):
"""TAMU Provider
Params
------
:param ``location``: The street address of the location you want geocoded.
:param ``city``: The city of the location to geocode.
:param ``state``: The state of the location to geocode.
:param ``zipcode``: The zipcode of the location to geocode.
:param ``key``: The API key (use API key "demo" for testing).
API Reference
-------------
https://geoservices.tamu.edu/Services/Geocode/WebService
"""
return get(location, provider='tamu', **kwargs)
def geocodefarm(location, **kwargs):
"""GeocodeFarm Provider
Params
------
:param ``location``: The string to search for. Usually a street address.
:param ``key``: (optional) API Key. Only Required for Paid Users.
:param ``lang``: (optional) 2 digit language code to return results in. Currently only "en"(English) or "de"(German) supported.
:param ``country``: (optional) The country to return results in. Used for biasing purposes and may not fully filter results to this specific country.
:param ``maxRows``: (default=1) Max number of results to fetch
API Reference
-------------
https://geocode.farm/geocoding/free-api-documentation/
"""
return get(location, provider='geocodefarm', **kwargs)
def tgos(location, **kwargs):
"""TGOS Provider
:param ``location``: Your search location you want geocoded.
:param ``language``: (default=taiwan) Use the following:
> taiwan
> english
> chinese
:param ``method``: (default=geocode) Use the following:
> geocode
API Reference
-------------
http://api.tgos.nat.gov.tw/TGOS_MAP_API/Web/Default.aspx
"""
return get(location, provider='tgos', **kwargs)
def uscensus(location, **kwargs):
"""US Census Provider
Params
------
:param ``location``: Your search location(s) you want geocoded.
:param ``benchmark``: (default=4) Use the following:
> Public_AR_Current or 4
> Public_AR_ACSYYYY or 8
> Public_AR_Census2010 or 9
:param ``vintage``: (default=4, not available with batch method) Use the following:
> Current_Current or 4
> Census2010_Current or 410
> ACS2013_Current or 413
> ACS2014_Current or 414
> ACS2015_Current or 415
> Current_ACS2015 or 8
> Census2010_ACS2015 or 810
> ACS2013_ACS2015 or 813
> ACS2014_ACS2015 or 814
> ACS2015_ACS2015 or 815
> Census2010_Census2010 or 910
> Census2000_Census2010 or 900
:param ``method``: (default=geocode) Use the following:
> geocode
> reverse
> batch
API Reference
-------------
https://geocoding.geo.census.gov/geocoder/Geocoding_Services_API.pdf
"""
return get(location, provider='uscensus', **kwargs)
def locationiq(location, **kwargs):
"""LocationIQ Provider
Params
------
:param ``location``: Your search location you want geocoded.
:param ``method``: (default=geocode) Use the following:
> geocode
> reverse
API Reference
-------------
https://locationiq.org/
"""
return get(location, provider='locationiq', **kwargs)
def gisgraphy(location, **kwargs):
"""Gisgraphy Provider
:param ``location``: Your search location you want geocoded.
"""
return get(location, provider='gisgraphy', **kwargs)

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

104
geocoder/arcgis.py Normal file
View File

@ -0,0 +1,104 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
import json
from geocoder.base import OneResult, MultipleResultsQuery
class ArcgisResult(OneResult):
def __init__(self, json_content):
# create safe shortcuts
self._feature = json_content.get('feature', {})
# proceed with super.__init__
super(ArcgisResult, self).__init__(json_content)
@property
def address(self):
return self.raw.get('name', '')
@property
def lat(self):
return self._feature.get('geometry', {}).get('y')
@property
def lng(self):
return self._feature.get('geometry', {}).get('x')
@property
def score(self):
return self._feature.get('attributes', {}).get('Score', '')
@property
def quality(self):
return self._feature.get('attributes', {}).get('Addr_Type', '')
@property
def bbox(self):
_extent = self.raw.get('extent')
if _extent:
south = _extent.get('ymin')
west = _extent.get('xmin')
north = _extent.get('ymax')
east = _extent.get('xmax')
return self._get_bbox(south, west, north, east)
class ArcgisQuery(MultipleResultsQuery):
"""
ArcGIS REST API
=======================
The World Geocoding Service finds addresses and places in all supported countries
from a single endpoint. The service can find point locations of addresses,
business names, and so on. The output points can be visualized on a map,
inserted as stops for a route, or loaded as input for a spatial analysis.
an address, retrieving imagery metadata, or creating a route.
API Reference
-------------
https://developers.arcgis.com/rest/geocode/api-reference/geocoding-find.htm
"""
provider = 'arcgis'
method = 'geocode'
_URL = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find'
_RESULT_CLASS = ArcgisResult
_KEY_MANDATORY = False
def _build_params(self, location, provider_key, **kwargs):
# backward compatitibility for 'limit' (now maxRows)
if 'limit' in kwargs:
logging.warning(
"argument 'limit' in OSM is deprecated and should be replaced with maxRows")
kwargs['maxRows'] = kwargs['limit']
# build params
return {
'f': 'json',
'text': location,
'maxLocations': kwargs.get('maxRows', 1),
}
def _adapt_results(self, json_response):
return json_response['locations']
def _catch_errors(self, json_response):
status = json_response.get('error')
if status:
self.error = status.get('code')
self.message = status.get('message')
self.details = status.get('details')
return self.error
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = ArcgisQuery('Toronto')
g.debug()
g = ArcgisQuery('Ottawa, Ontario', maxRows=5)
print(json.dumps(g.geojson, indent=4))
print([result.address for result in g][:3])

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,98 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.base import OneResult
from geocoder.arcgis import ArcgisQuery
from geocoder.location import Location
class ArcgisReverseResult(OneResult):
@property
def ok(self):
return bool(self.address)
@property
def lat(self):
return self.raw['location'].get('y')
@property
def lng(self):
return self.raw['location'].get('x')
@property
def address(self):
return self.raw['address'].get('Match_addr')
@property
def city(self):
return self.raw['address'].get('City')
@property
def neighborhood(self):
return self.raw['address'].get('Neighbourhood')
@property
def region(self):
return self.raw['address'].get('Region')
@property
def country(self):
return self.raw['address'].get('CountryCode')
@property
def postal(self):
return self.raw['address'].get('Postal')
@property
def state(self):
return self.raw['address'].get('Region')
class ArcgisReverse(ArcgisQuery):
"""
ArcGIS REST API
=======================
The World Geocoding Service finds addresses and places in all supported countries
from a single endpoint. The service can find point locations of addresses,
business names, and so on. The output points can be visualized on a map,
inserted as stops for a route, or loaded as input for a spatial analysis.
an address, retrieving imagery metadata, or creating a route.
API Reference
-------------
https://developers.arcgis.com/rest/geocode/api-reference/geocoding-reverse-geocode.htm
"""
provider = 'arcgis'
method = 'reverse'
_URL = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode'
_RESULT_CLASS = ArcgisReverseResult
def _build_params(self, location, provider_key, **kwargs):
location = Location(location)
return {
'location': u'{}, {}'.format(location.lng, location.lat),
'f': 'pjson',
'distance': kwargs.get('distance', 50000),
'outSR': kwargs.get('outSR', '')
}
def _adapt_results(self, json_response):
return [json_response]
def _catch_errors(self, json_response):
error = json_response.get('error', None)
if error:
self.error = error['message']
return self.error
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = ArcgisReverse("45.404702, -75.704150")
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

135
geocoder/baidu.py Normal file
View File

@ -0,0 +1,135 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from collections import OrderedDict
import logging
import re
import six
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import baidu_key, baidu_security_key
class BaiduResult(OneResult):
@property
def lat(self):
return self.raw.get('location', {}).get('lat')
@property
def lng(self):
return self.raw.get('location', {}).get('lng')
@property
def quality(self):
return self.raw.get('level')
@property
def confidence(self):
return self.raw.get('confidence')
class BaiduQuery(MultipleResultsQuery):
"""
Baidu Geocoding API
===================
Baidu Maps Geocoding API is a free open the API, the default quota
one million times / day.
Params
------
:param location: Your search location you want geocoded.
:param key: Baidu API key.
:param referer: Baidu API referer website.
References
----------
API Documentation: http://developer.baidu.com/map
Get Baidu Key: http://lbsyun.baidu.com/apiconsole/key
"""
provider = 'baidu'
method = 'geocode'
_URL = 'http://api.map.baidu.com/geocoder/v2/'
_RESULT_CLASS = BaiduResult
_KEY = baidu_key
def _build_params(self, location, provider_key, **kwargs):
coordtype = kwargs.get('coordtype', 'wgs84ll')
params = {
'address': re.sub('[ ,]', '%', location),
'output': 'json',
'ret_coordtype': coordtype,
'ak': provider_key,
}
# adapt params to authentication method
self.security_key = kwargs.get('sk', baidu_security_key)
if self.security_key:
return self._encode_params(params)
else:
return params
def _encode_params(self, params):
# maintain the order of the parameters during signature creation when returning the results
# signature is added to the end of the parameters
ordered_params = sorted([(k, v)
for (k, v) in params.items() if v])
params = OrderedDict(ordered_params)
# urlencode with Chinese symbols sabotage the query
params['sn'] = self._sign_url(
'/geocoder/v2/',
params,
self.security_key
)
return params
def _sign_url(self, base_url, params, security_key):
"""
Signs a request url with a security key.
"""
import hashlib
if six.PY3:
from urllib.parse import urlencode, quote, quote_plus
else:
from urllib import urlencode, quote, quote_plus
if not base_url or not self.security_key:
return None
params = params.copy()
address = params.pop('address')
url = base_url + '?address=' + address + '&' + urlencode(params)
encoded_url = quote(url, safe="/:=&?#+!$,;'@()*[]")
signature = quote_plus(encoded_url + self.security_key).encode('utf-8')
encoded_signature = hashlib.md5(signature).hexdigest()
return encoded_signature
def _build_headers(self, provider_key, **kwargs):
return {'Referer': kwargs.get('referer', 'http://developer.baidu.com')}
def _adapt_results(self, json_response):
return [json_response['result']]
def _catch_errors(self, json_response):
status_code = json_response.get('status')
if status_code != 0:
self.status_code = status_code
self.error = json_response.get('message')
return self.error
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = BaiduQuery('将台路', key='')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

91
geocoder/baidu_reverse.py Normal file
View File

@ -0,0 +1,91 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.location import Location
from geocoder.base import OneResult
from geocoder.baidu import BaiduQuery
class BaiduReverseResult(OneResult):
@property
def ok(self):
return bool(self.address)
@property
def address(self):
return self.raw['formatted_address']
@property
def country(self):
return self.raw['addressComponent']['country']
@property
def province(self):
return self.raw['addressComponent']['province']
@property
def state(self):
return self.raw['addressComponent']['province']
@property
def city(self):
return self.raw['addressComponent']['city']
@property
def district(self):
return self.raw['addressComponent']['district']
@property
def street(self):
return self.raw['addressComponent']['street']
@property
def housenumber(self):
return self.raw['addressComponent']['street_number']
class BaiduReverse(BaiduQuery):
"""
Baidu Geocoding API
===================
Baidu Maps Geocoding API is a free open the API, the default quota
one million times / day.
Params
------
:param location: Your search location you want geocoded.
:param key: Baidu API key.
:param referer: Baidu API referer website.
References
----------
API Documentation: http://developer.baidu.com/map
Get Baidu Key: http://lbsyun.baidu.com/apiconsole/key
"""
provider = 'baidu'
method = 'reverse'
_URL = 'http://api.map.baidu.com/geocoder/v2/'
_RESULT_CLASS = BaiduReverseResult
def _build_params(self, location, provider_key, **kwargs):
location = Location(location)
params = {
'location': str(location),
'ret_coordtype': kwargs.get('coordtype', 'wgs84ll'),
'output': 'json',
'ak': provider_key
}
if ('lang_code' in kwargs):
params['accept-language'] = kwargs['lang_code']
return params
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = BaiduReverse("39.983424,116.32298", key='')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

606
geocoder/base.py Normal file
View File

@ -0,0 +1,606 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import, print_function
from builtins import str
import requests
import sys
import json
import six
import logging
from io import StringIO
from collections import OrderedDict
is_python2 = sys.version_info < (3, 0)
if is_python2:
# python 2.7
from urlparse import urlparse
class MutableSequence(object):
def index(self, v, **kwargs): return self._list.index(v, **kwargs) # noqa
def count(self, v): return self._list.count(v) # noqa
def pop(self, i=-1): return self._list.pop(i) # noqa
def remove(self, v): self._list.remove(v) # noqa
def __iter__(self): return iter(self._list) # noqa
def __contains__(self, v): return self._list.__contains__(v) # noqa
def __eq__(self, other): return self._list == other # noqa
else:
# python >3.3
from collections.abc import MutableSequence
from urllib.parse import urlparse
from geocoder.distance import Distance # noqa
LOGGER = logging.getLogger(__name__)
class OneResult(object):
""" Container for one (JSON) object returned by the various web services"""
_TO_EXCLUDE = ['parse', 'json', 'url', 'fieldnames', 'help', 'debug',
'short_name', 'api', 'content', 'params',
'street_number', 'api_key', 'key', 'id', 'x', 'y',
'latlng', 'headers', 'timeout', 'wkt', 'locality',
'province', 'rate_limited_get', 'osm', 'route', 'schema',
'properties', 'geojson', 'tree', 'error', 'proxies', 'road',
'xy', 'northeast', 'northwest', 'southeast', 'southwest',
'road_long', 'city_long', 'state_long', 'country_long',
'postal_town_long', 'province_long', 'road_long',
'street_long', 'interpolated', 'method', 'geometry', 'session']
def __init__(self, json_content):
self.raw = json_content
# attributes required to compute bbox
self.northeast = []
self.northwest = []
self.southeast = []
self.southwest = []
# attributes returned in JSON format
self.fieldnames = []
self.json = {}
self._parse_json_with_fieldnames()
# Essential attributes for Quality Control
@property # noqa
def lat(self): return '' # noqa
@property # noqa
def lng(self): return '' # noqa
@property # noqa
def accuracy(self): return '' # noqa
@property # noqa
def quality(self): return '' # noqa
# Bounding Box attributes
@property # noqa
def bbox(self): return {} # noqa
# Essential attributes for Street Address
@property # noqa
def address(self): return '' # noqa
@property # noqa
def housenumber(self): return '' # noqa
@property # noqa
def street(self): return '' # noqa
@property # noqa
def city(self): return '' # noqa
@property # noqa
def state(self): return '' # noqa
@property # noqa
def country(self): return '' # noqa
@property # noqa
def postal(self): return '' # noqa
def __repr__(self):
""" Display [address] if available; [lat,lng] otherwise"""
if self.address:
return u'[{0}]'.format(six.text_type(self.address))
else:
return u'[{0},{1}]'.format(self.lat, self.lng)
def _parse_json_with_fieldnames(self):
""" Parse the raw JSON with all attributes/methods defined in the class, except for the
ones defined starting with '_' or flagged in cls._TO_EXCLUDE.
The final result is stored in self.json
"""
for key in dir(self):
if not key.startswith('_') and key not in self._TO_EXCLUDE:
self.fieldnames.append(key)
value = getattr(self, key)
if value:
self.json[key] = value
# Add OK attribute even if value is "False"
self.json['ok'] = self.ok
@property
def ok(self):
return bool(self.lng and self.lat)
@property
def status(self):
if self.ok:
return 'OK'
if not self.address:
return 'ERROR - No results found'
return 'ERROR - No Geometry'
def debug(self, verbose=True):
with StringIO() as output:
print(u'\n', file=output)
print(u'From provider\n', file=output)
print(u'-----------\n', file=output)
print(str(json.dumps(self.raw, indent=4)), file=output)
print(u'\n', file=output)
print(u'Cleaned json\n', file=output)
print(u'-----------\n', file=output)
print(str(json.dumps(self.json, indent=4)), file=output)
print(u'\n', file=output)
print(u'OSM Quality\n', file=output)
print(u'-----------\n', file=output)
osm_count = 0
for key in self.osm:
if 'addr:' in key:
if self.json.get(key.replace('addr:', '')):
print(u'- [x] {0}\n'.format(key), file=output)
osm_count += 1
else:
print(u'- [ ] {0}\n'.format(key), file=output)
print(u'({0}/{1})\n'.format(osm_count, len(self.osm) - 2), file=output)
print(u'\n', file=output)
print(u'Fieldnames\n', file=output)
print(u'----------\n', file=output)
fields_count = 0
for fieldname in self.fieldnames:
if self.json.get(fieldname):
print(u'- [x] {0}\n'.format(fieldname), file=output)
fields_count += 1
else:
print(u'- [ ] {0}\n'.format(fieldname), file=output)
print(u'({0}/{1})\n'.format(fields_count, len(self.fieldnames)), file=output)
# print in verbose mode
if verbose:
print(output.getvalue())
# return stats
return [osm_count, fields_count]
def _get_bbox(self, south, west, north, east):
if all([south, east, north, west]):
# South Latitude, West Longitude, North Latitude, East Longitude
self.south = float(south)
self.west = float(west)
self.north = float(north)
self.east = float(east)
# Bounding Box Corners
self.northeast = [self.north, self.east]
self.northwest = [self.north, self.west]
self.southwest = [self.south, self.west]
self.southeast = [self.south, self.east]
# GeoJSON bbox
self.westsouth = [self.west, self.south]
self.eastnorth = [self.east, self.north]
return dict(northeast=self.northeast, southwest=self.southwest)
return {}
@property
def confidence(self):
if self.bbox:
# Units are measured in Kilometers
distance = Distance(self.northeast, self.southwest, units='km')
for score, maximum in [(10, 0.25),
(9, 0.5),
(8, 1),
(7, 5),
(6, 7.5),
(5, 10),
(4, 15),
(3, 20),
(2, 25)]:
if distance < maximum:
return score
if distance >= 25:
return 1
# Cannot determine score
return 0
@property
def geometry(self):
if self.ok:
return {
'type': 'Point',
'coordinates': [self.x, self.y]}
return {}
@property
def osm(self):
osm = dict()
if self.ok:
osm['x'] = self.x
osm['y'] = self.y
if self.housenumber:
osm['addr:housenumber'] = self.housenumber
if self.road:
osm['addr:street'] = self.road
if self.city:
osm['addr:city'] = self.city
if self.state:
osm['addr:state'] = self.state
if self.country:
osm['addr:country'] = self.country
if self.postal:
osm['addr:postal'] = self.postal
if hasattr(self, 'population'):
if self.population:
osm['population'] = self.population
return osm
@property
def geojson(self):
feature = {
'type': 'Feature',
'properties': self.json,
}
if self.bbox:
feature['bbox'] = [self.west, self.south, self.east, self.north]
feature['properties']['bbox'] = feature['bbox']
if self.geometry:
feature['geometry'] = self.geometry
return feature
@property
def wkt(self):
if self.ok:
return 'POINT({x} {y})'.format(x=self.x, y=self.y)
return ''
@property
def xy(self):
if self.ok:
return [self.lng, self.lat]
return []
@property
def latlng(self):
if self.ok:
return [self.lat, self.lng]
return []
@property
def y(self):
return self.lat
@property
def x(self):
return self.lng
@property
def locality(self):
return self.city
@property
def province(self):
return self.state
@property
def street_number(self):
return self.housenumber
@property
def road(self):
return self.street
@property
def route(self):
return self.street
class MultipleResultsQuery(MutableSequence):
""" Will replace the Base class to support multiple results, with the following differences :
- split class into 2 parts :
- OneResult to actually store a (JSON) object from provider
- MultipleResultsQuery to manage the query
- class variables moved into instance
- remaining class variables are names with convention: _CAPITALS
- self.url derived from class var cls.URL, which must be a valid URL
- self.timeout has default value from class var cls.TIMEOUT
"""
_URL = None
_RESULT_CLASS = None
_KEY = None
_KEY_MANDATORY = True
_TIMEOUT = 5.0
@staticmethod
def _is_valid_url(url):
""" Helper function to validate that URLs are well formed, i.e that it contains a valid
protocol and a valid domain. It does not actually check if the URL exists
"""
try:
parsed = urlparse(url)
mandatory_parts = [parsed.scheme, parsed.netloc]
return all(mandatory_parts)
except:
return False
@classmethod
def _is_valid_result_class(cls):
return issubclass(cls._RESULT_CLASS, OneResult)
@classmethod
def _get_api_key(cls, key=None):
# Retrieves API Key from method argument first, then from Environment variables
key = key or cls._KEY
# raise exception if not valid key found
if not key and cls._KEY_MANDATORY:
raise ValueError('Provide API Key')
return key
def __init__(self, location, **kwargs):
super(MultipleResultsQuery, self).__init__()
self._list = []
# check validity of _URL
if not self._is_valid_url(self._URL):
raise ValueError("Subclass must define a valid URL. Got %s", self._URL)
# override with kwargs IF given AND not empty string
self.url = kwargs.get('url', self._URL) or self._URL
# double check url, just in case it has been overwritten by kwargs
if not self._is_valid_url(self.url):
raise ValueError("url not valid. Got %s", self.url)
# check validity of Result class
if not self._is_valid_result_class():
raise ValueError(
"Subclass must define _RESULT_CLASS from 'OneResult'. Got %s", self._RESULT_CLASS)
self.one_result = self._RESULT_CLASS
# check validity of provider key
provider_key = self._get_api_key(kwargs.pop('key', ''))
# point to geocode, as a string or coordinates
self.location = location
# set attributes to manage query
self.encoding = kwargs.get('encoding', 'utf-8')
self.timeout = kwargs.get('timeout', self._TIMEOUT)
self.proxies = kwargs.get('proxies', '')
self.session = kwargs.get('session', requests.Session())
# headers can be overriden in _build_headers
self.headers = self._build_headers(provider_key, **kwargs).copy()
self.headers.update(kwargs.get('headers', {}))
# params can be overriden in _build_params
# it is an OrderedDict in order to preserve the order of the url query parameters
self.params = OrderedDict(self._build_params(location, provider_key, **kwargs))
self.params.update(kwargs.get('params', {}))
# results of query (set by _connect)
self.status_code = None
self.response = None
self.error = False
# pointer to result where to delegates calls
self.current_result = None
# hook for children class to finalize their setup before the query
self._before_initialize(location, **kwargs)
# query and parse results
self._initialize()
def __getitem__(self, key):
return self._list[key]
def __setitem__(self, key, value):
self._list[key] = value
def __delitem__(self, key):
del self._list[key]
def __len__(self):
return len(self._list)
def insert(self, index, value):
self._list.insert(index, value)
def add(self, value):
self._list.append(value)
def __repr__(self):
base_repr = u'<[{0}] {1} - {2} {{0}}>'.format(
self.status,
self.provider.title(),
self.method.title()
)
if len(self) == 0:
return base_repr.format(u'[empty]')
elif len(self) == 1:
return base_repr.format(repr(self[0]))
else:
return base_repr.format(u'#%s results' % len(self))
def _build_headers(self, provider_key, **kwargs):
"""Will be overridden according to the targetted web service"""
return {}
def _build_params(self, location, provider_key, **kwargs):
"""Will be overridden according to the targetted web service"""
return {}
def _before_initialize(self, location, **kwargs):
"""Can be overridden to finalize setup before the query"""
pass
def _initialize(self):
# query URL and get valid JSON (also stored in self.json)
json_response = self._connect()
# catch errors
has_error = self._catch_errors(
json_response) if json_response else True
# creates instances for results
if not has_error:
self._parse_results(json_response)
def _connect(self):
""" - Query self.url (validated cls._URL)
- Analyse reponse and set status, errors accordingly
- On success:
returns the content of the response as a JSON object
This object will be passed to self._parse_json_response
"""
self.status_code = 'Unknown'
try:
# make request and get response
self.response = response = self.rate_limited_get(
self.url,
params=self.params,
headers=self.headers,
timeout=self.timeout,
proxies=self.proxies
)
# check that response is ok
self.status_code = response.status_code
response.raise_for_status()
# rely on json method to get non-empty well formatted JSON
json_response = response.json()
self.url = response.url
LOGGER.info("Requested %s", self.url)
except requests.exceptions.RequestException as err:
# store real status code and error
self.error = u'ERROR - {}'.format(str(err))
LOGGER.error("Status code %s from %s: %s",
self.status_code, self.url, self.error)
# return False
return False
# return response within its JSON format
return json_response
def rate_limited_get(self, url, **kwargs):
""" By default, simply wraps a session.get request"""
return self.session.get(url, **kwargs)
def _adapt_results(self, json_response):
""" Allow children classes to format json_response into an array of objects
OVERRIDE TO FETCH the correct array of objects when necessary
"""
return json_response
def _parse_results(self, json_response):
""" Creates instances of self.one_result (validated cls._RESULT_CLASS)
from JSON results retrieved by self._connect
params: array of objects (dictionnaries)
"""
for json_dict in self._adapt_results(json_response):
self.add(self.one_result(json_dict))
# set default result to use for delegation
self.current_result = len(self) > 0 and self[0]
def _catch_errors(self, json_response):
""" Checks the JSON returned from the provider and flag errors if necessary"""
return self.error
@property
def ok(self):
return len(self) > 0
@property
def status(self):
if self.ok:
return 'OK'
elif self.error:
return self.error
elif len(self) == 0:
return 'ERROR - No results found'
else:
return 'ERROR - Unhandled Exception'
@property
def geojson(self):
geojson_results = [result.geojson for result in self]
features = {
'type': 'FeatureCollection',
'features': geojson_results
}
return features
def debug(self, verbose=True):
with StringIO() as output:
print(u'===\n', file=output)
print(str(repr(self)), file=output)
print(u'===\n', file=output)
print(u'\n', file=output)
print(u'#res: {}\n'.format(len(self)), file=output)
print(u'code: {}\n'.format(self.status_code), file=output)
print(u'url: {}\n'.format(self.url), file=output)
stats = []
if self.ok:
for index, result in enumerate(self):
print(u'\n', file=output)
print(u'Details for result #{}\n'.format(index + 1), file=output)
print(u'---\n', file=output)
stats.append(result.debug())
else:
print(self.status, file=output)
if verbose:
print(output.getvalue())
return stats
# Delegation to current result
def set_default_result(self, index):
""" change the result used to delegate the calls to. The provided index should be in the
range of results, otherwise it will raise an exception
"""
self.current_result = self[index]
def __getattr__(self, name):
""" Called when an attribute lookup has not found the attribute in the usual places (i.e.
it is not an instance attribute nor is it found in the class tree for self). name is
the attribute name. This method should return the (computed) attribute value or raise
an AttributeError exception.
Note that if the attribute is found through the normal mechanism, __getattr__() is not called.
"""
if not self.ok:
return None
if self.current_result is None:
raise AttributeError("%s not found on %s, and current_result is None".format(
name, self.__class__.__name__
))
return getattr(self.current_result, name)

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

180
geocoder/bing.py Normal file
View File

@ -0,0 +1,180 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import bing_key
import re
class BingResult(OneResult):
def __init__(self, json_content):
# create safe shortcuts
self._point = json_content.get('point', {})
self._address = json_content.get('address', {})
# proceed with super.__init__
super(BingResult, self).__init__(json_content)
@property
def lat(self):
coord = self._point['coordinates']
if coord:
return coord[0]
@property
def lng(self):
coord = self._point['coordinates']
if coord:
return coord[1]
@property
def address(self):
return self._address.get('formattedAddress')
@property
def housenumber(self):
if self.street:
expression = r'\d+'
pattern = re.compile(expression)
match = pattern.search(self.street, re.UNICODE)
if match:
return match.group(0)
@property
def street(self):
return self._address.get('addressLine')
@property
def neighborhood(self):
return self._address.get('neighborhood')
@property
def city(self):
return self._address.get('locality')
@property
def state(self):
return self._address.get('adminDistrict')
@property
def country(self):
return self._address.get('countryRegion')
@property
def quality(self):
return self.raw.get('entityType')
@property
def accuracy(self):
return self.raw.get('calculationMethod')
@property
def postal(self):
return self._address.get('postalCode')
@property
def bbox(self):
_bbox = self.raw.get('bbox')
if _bbox:
south = _bbox[0]
north = _bbox[2]
west = _bbox[1]
east = _bbox[3]
return self._get_bbox(south, west, north, east)
class BingQuery(MultipleResultsQuery):
"""
Bing Maps REST Services
=======================
The Bing Maps REST Services Application Programming Interface (API)
provides a Representational State Transfer (REST) interface to
perform tasks such as creating a static map with pushpins, geocoding
an address, retrieving imagery metadata, or creating a route.
API Reference
-------------
http://msdn.microsoft.com/en-us/library/ff701714.aspx
Get Bing key
------------
https://www.bingmapsportal.com/
"""
provider = 'bing'
method = 'geocode'
_URL = 'http://dev.virtualearth.net/REST/v1/Locations'
_RESULT_CLASS = BingResult
_KEY = bing_key
def _build_headers(self, provider_key, **kwargs):
return {
'Referer': "http://addxy.com/",
'User-agent': 'Mozilla/5.0'
}
def _build_params(self, location, provider_key, **kwargs):
return {
'q': location,
'o': 'json',
'inclnb': 1,
'key': provider_key,
'maxResults': kwargs.get('maxRows', 1)
}
def _catch_errors(self, json_response):
status = json_response['statusDescription']
if not status == 'OK':
self.error = status
return self.error
def _adapt_results(self, json_response):
# extract the array of JSON objects
sets = json_response['resourceSets']
if sets:
return sets[0]['resources']
return []
class BingQueryDetail(MultipleResultsQuery):
provider = 'bing'
method = 'details'
_URL = 'http://dev.virtualearth.net/REST/v1/Locations'
_RESULT_CLASS = BingResult
_KEY = bing_key
def _build_params(self, location, provider_key, **kwargs):
return {
'adminDistrict': kwargs.get('adminDistrict'),
'countryRegion': kwargs.get('countryRegion'),
'locality': kwargs.get('locality'),
'postalCode': kwargs.get('countryRegion'),
'addressLine': kwargs.get('addressLine', location),
'o': 'json',
'inclnb': 1,
'key': provider_key,
'maxResults': kwargs.get('maxRows', 1)
}
def _catch_errors(self, json_response):
status = json_response['statusDescription']
if not status == 'OK':
self.error = status
return self.error
def _adapt_results(self, json_response):
# extract the array of JSON objects
sets = json_response['resourceSets']
if sets:
return sets[0]['resources']
return []
if __name__ == '__main__':
g = BingQuery('453 Booth Street, Ottawa Ontario')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

179
geocoder/bing_batch.py Normal file
View File

@ -0,0 +1,179 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import, print_function
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import bing_key
import time
import io
import requests
import logging
import sys
PY2 = sys.version_info < (3, 0)
csv_io = io.BytesIO if PY2 else io.StringIO
LOGGER = logging.getLogger(__name__)
class BingBatchResult(OneResult):
def __init__(self, content):
self._content = content
@property
def lat(self):
coord = self._content
if coord:
return coord[0]
@property
def lng(self):
coord = self._content
if coord:
return coord[1]
def debug(self, verbose=True):
with csv_io() as output:
print('\n', file=output)
print('{} result\n'.format(self.__class__.__name__), file=output)
print('-----------\n', file=output)
print(self._content, file=output)
if verbose:
print(output.getvalue())
return [None, None]
class BingBatch(MultipleResultsQuery):
"""
Bing Maps REST Services
=======================
The Bing Maps REST Services Application Programming Interface (API)
provides a Representational State Transfer (REST) interface to
perform tasks such as creating a static map with pushpins, geocoding
an address, retrieving imagery metadata, or creating a route.
API Reference
-------------
http://msdn.microsoft.com/en-us/library/ff701714.aspx
Dataflow Reference
------------------
https://msdn.microsoft.com/en-us/library/ff701733.aspx
"""
provider = 'bing'
_URL = u'http://spatial.virtualearth.net/REST/v1/Dataflows/Geocode'
_BATCH_TIMEOUT = 60
_BATCH_WAIT = 5
_RESULT_CLASS = BingBatchResult
_KEY = bing_key
def extract_resource_id(self, response):
for rs in response['resourceSets']:
for resource in rs['resources']:
if 'id' in resource:
return resource['id']
raise LookupError('No job ID returned from Bing batch call')
def is_job_done(self, job_id):
url = u'http://spatial.virtualearth.net/REST/v1/Dataflows/Geocode/{}'.format(job_id)
response = self.session.get(
url,
params={'key': self.provider_key},
timeout=self.timeout,
proxies=self.proxies
)
for rs in response.json()['resourceSets']:
for resource in rs['resources']:
if resource['id'] == job_id:
if resource['status'] == 'Aborted':
raise LookupError('Bing job aborted')
return resource['status'] == 'Completed'
raise LookupError('Job ID not found in Bing answer - something is wrong')
def get_job_result(self, job_id):
url = u'http://spatial.virtualearth.net/REST/v1/Dataflows/Geocode/{}/output/succeeded'.format(job_id)
response = self.session.get(
url,
params={'key': self.provider_key},
timeout=self.timeout,
proxies=self.proxies
)
return response.content
def _build_params(self, locations, provider_key, **kwargs):
self.batch = self.generate_batch(locations)
self.locations_length = len(locations)
self.provider_key = provider_key
self._BATCH_TIMEOUT = kwargs.get('timeout', 60)
return {
'input': 'csv',
'key': provider_key
}
def _build_headers(self, provider_key, **kwargs):
return {'Content-Type': 'text/plain'}
def _connect(self):
self.status_code = 'Unknown'
try:
self.response = response = self.session.post(
self.url,
data=self.batch,
params=self.params,
headers=self.headers,
timeout=self.timeout,
proxies=self.proxies
)
# check that response is ok
self.status_code = response.status_code
response.raise_for_status()
# rely on json method to get non-empty well formatted JSON
json_response = response.json()
self.url = response.url
LOGGER.info("Requested %s", self.url)
# get the resource/job id
resource_id = self.extract_resource_id(json_response)
elapsed = 0
# try for _BATCH_TIMEOUT seconds to retrieve the results of that job
while (elapsed < self._BATCH_TIMEOUT):
if self.is_job_done(resource_id):
return self.get_job_result(resource_id)
elapsed = elapsed + self._BATCH_WAIT
time.sleep(self._BATCH_WAIT)
LOGGER.error("Job was not finished in time.")
except (requests.exceptions.RequestException, LookupError) as err:
# store real status code and error
self.error = u'ERROR - {}'.format(str(err))
LOGGER.error("Status code %s from %s: %s",
self.status_code, self.url, self.error)
return False
def _parse_results(self, response):
rows = self._adapt_results(response)
# re looping through the results to give them back in their original order
for idx in range(0, self.locations_length):
self.add(self.one_result(rows.get(str(idx), None)))
self.current_result = len(self) > 0 and self[0]

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,81 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import, print_function
from geocoder.bing_batch import BingBatch, BingBatchResult
import io
import csv
import sys
PY2 = sys.version_info < (3, 0)
csv_io = io.BytesIO if PY2 else io.StringIO
csv_encode = (lambda input: input) if PY2 else (lambda input: input.encode('utf-8'))
csv_decode = (lambda input: input) if PY2 else (lambda input: input.decode('utf-8'))
class BingBatchForwardResult(BingBatchResult):
@property
def lat(self):
coord = self._content
if coord:
return float(coord[0])
@property
def lng(self):
coord = self._content
if coord:
return float(coord[1])
@property
def ok(self):
return bool(self._content)
def debug(self, verbose=True):
with csv_io() as output:
print('\n', file=output)
print('Bing Batch result\n', file=output)
print('-----------\n', file=output)
print(self._content, file=output)
if verbose:
print(output.getvalue())
return [None, None]
class BingBatchForward(BingBatch):
method = 'batch'
_RESULT_CLASS = BingBatchForwardResult
def generate_batch(self, addresses):
out = csv_io()
writer = csv.writer(out)
writer.writerow([
'Id',
'GeocodeRequest/Query',
'GeocodeResponse/Point/Latitude',
'GeocodeResponse/Point/Longitude'
])
for idx, address in enumerate(addresses):
writer.writerow([idx, address, None, None])
return csv_encode("Bing Spatial Data Services, 2.0\n{}".format(out.getvalue()))
def _adapt_results(self, response):
result = csv_io(csv_decode(response))
# Skipping first line with Bing header
next(result)
rows = {}
for row in csv.DictReader(result):
rows[row['Id']] = [row['GeocodeResponse/Point/Latitude'], row['GeocodeResponse/Point/Longitude']]
return rows
if __name__ == '__main__':
g = BingBatchForward(['Denver,CO', 'Boulder,CO'], key=None)
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,111 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import, print_function
from geocoder.bing_batch import BingBatch, BingBatchResult
import io
import csv
import sys
PY2 = sys.version_info < (3, 0)
csv_io = io.BytesIO if PY2 else io.StringIO
csv_encode = (lambda input: input) if PY2 else (lambda input: input.encode('utf-8'))
csv_decode = (lambda input: input) if PY2 else (lambda input: input.decode('utf-8'))
class BingBatchReverseResult(BingBatchResult):
@property
def address(self):
address = self._content
if address:
return address[0]
@property
def city(self):
city = self._content
if city:
return city[1]
@property
def postal(self):
postal = self._content
if postal:
return postal[2]
@property
def state(self):
state = self._content
if state:
return state[3]
@property
def country(self):
country = self._content
if country:
return country[4]
@property
def ok(self):
return bool(self._content)
def debug(self, verbose=True):
with csv_io() as output:
print('\n', file=output)
print('Bing Batch result\n', file=output)
print('-----------\n', file=output)
print(self._content, file=output)
if verbose:
print(output.getvalue())
return [None, None]
class BingBatchReverse(BingBatch):
method = 'batch_reverse'
_RESULT_CLASS = BingBatchReverseResult
def generate_batch(self, locations):
out = csv_io()
writer = csv.writer(out)
writer.writerow([
'Id',
'ReverseGeocodeRequest/Location/Latitude',
'ReverseGeocodeRequest/Location/Longitude',
'GeocodeResponse/Address/FormattedAddress',
'GeocodeResponse/Address/Locality',
'GeocodeResponse/Address/PostalCode',
'GeocodeResponse/Address/AdminDistrict',
'GeocodeResponse/Address/CountryRegion'
])
for idx, location in enumerate(locations):
writer.writerow([idx, location[0], location[1], None, None, None, None, None])
return csv_encode("Bing Spatial Data Services, 2.0\n{}".format(out.getvalue()))
def _adapt_results(self, response):
# print(type(response))
result = csv_io(csv_decode(response))
# Skipping first line with Bing header
next(result)
rows = {}
for row in csv.DictReader(result):
rows[row['Id']] = [
row['GeocodeResponse/Address/FormattedAddress'],
row['GeocodeResponse/Address/Locality'],
row['GeocodeResponse/Address/PostalCode'],
row['GeocodeResponse/Address/AdminDistrict'],
row['GeocodeResponse/Address/CountryRegion']
]
return rows
if __name__ == '__main__':
g = BingBatchReverse([(40.7943, -73.970859), (48.845580, 2.321807)], key=None)
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

48
geocoder/bing_reverse.py Normal file
View File

@ -0,0 +1,48 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.bing import BingResult, BingQuery
from geocoder.location import Location
class BingReverseResult(BingResult):
@property
def ok(self):
return bool(self.address)
class BingReverse(BingQuery):
"""
Bing Maps REST Services
=======================
The Bing Maps REST Services Application Programming Interface (API)
provides a Representational State Transfer (REST) interface to
perform tasks such as creating a static map with pushpins, geocoding
an address, retrieving imagery metadata, or creating a route.
API Reference
-------------
http://msdn.microsoft.com/en-us/library/ff701714.aspx
"""
provider = 'bing'
method = 'reverse'
_URL = u'http://dev.virtualearth.net/REST/v1/Locations/{0}'
def _build_params(self, location, provider_key, **kwargs):
return {
'o': 'json',
'key': provider_key,
'maxResults': 1,
}
def _before_initialize(self, location, **kwargs):
self.url = self.url.format(str(Location(location)))
if __name__ == '__main__':
g = BingReverse([45.4049053, -75.7077965], key=None)
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

170
geocoder/canadapost.py Normal file
View File

@ -0,0 +1,170 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import canadapost_key_getter
class CanadapostIdResult(OneResult):
@property
def ok(self):
return bool(self.item_id)
@property
def item_id(self):
return self.raw.get('Id')
@property
def next_action(self):
return self.raw.get('Next')
class CanadapostIdQuery(MultipleResultsQuery):
provider = 'canadapost'
method = 'id'
_URL = 'https://ws1.postescanada-canadapost.ca/AddressComplete/Interactive/Find/v2.10/json3ex.ws'
_RESULT_CLASS = CanadapostIdResult
_KEY_MANDATORY = False
def _build_params(self, location, provider_key, **kwargs):
if not provider_key:
provider_key = canadapost_key_getter(**kwargs)
return {
'Key': provider_key,
'LastId': kwargs.get('last_id', ''),
'Country': kwargs.get('country', 'ca'),
'SearchFor': 'Everything',
'SearchTerm': location,
'LanguagePreference': kwargs.get('language', 'en'),
'$cache': 'true'
}
def _adapt_results(self, json_response):
return json_response['Items']
class CanadapostResult(OneResult):
@property
def ok(self):
return bool(self.postal)
@property
def quality(self):
return self.raw.get('Type')
@property
def accuracy(self):
return self.raw.get('DataLevel')
@property
def address(self):
return self.raw.get('Line1')
@property
def postal(self):
return self.raw.get('PostalCode')
@property
def housenumber(self):
return self.raw.get('BuildingNumber')
@property
def street(self):
return self.raw.get('Street')
@property
def city(self):
return self.raw.get('City')
@property
def state(self):
return self.raw.get('ProvinceName')
@property
def country(self):
return self.raw.get('CountryName')
@property
def unit(self):
return self.raw.get('SubBuilding')
@property
def domesticId(self):
return self.raw.get('DomesticId')
@property
def label(self):
return self.raw.get('Label')
class CanadapostQuery(MultipleResultsQuery):
"""
Addres Complete API
=======================
The next generation of address finders, AddressComplete uses
intelligent, fast searching to improve data accuracy and relevancy.
Simply start typing a business name, address or Postal Code
and AddressComplete will suggest results as you go.
Params
------
:param ``location``: Your search location you want geocoded.
:param ``key``: (optional) API Key from CanadaPost Address Complete.
:param ``language``: (default=en) Output language preference.
:param ``country``: (default=ca) Geofenced query by country.
API Reference
-------------
https://www.canadapost.ca/pca/
"""
provider = 'canadapost'
method = 'geocode'
_URL = 'https://ws1.postescanada-canadapost.ca/AddressComplete/Interactive/RetrieveFormatted/v2.10/json3ex.ws'
_RESULT_CLASS = CanadapostResult
_KEY_MANDATORY = False
def _build_params(self, location, provider_key, **kwargs):
if not provider_key:
provider_key = canadapost_key_getter(**kwargs)
self.key = provider_key
last_id = ''
next_action = 'Find'
while next_action == 'Find':
ids = CanadapostIdQuery(location, key=provider_key, last_id=last_id, **kwargs)
next_action = ids.next_action
last_id = ids.item_id
if not ids.item_id:
raise ValueError("Could not get any Id for given location")
return {
'Key': provider_key,
'Id': ids.item_id,
'Source': '',
'MaxResults': kwargs.get('maxRows', 1),
'cache': 'true'
}
def _adapt_results(self, json_response):
return json_response['Items']
@property
def canadapost_api_key(self):
return self.key
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = CanadapostQuery("453 Booth Street, ON")
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

75
geocoder/cli.py Normal file
View File

@ -0,0 +1,75 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import click
import json
import geocoder
import os
import fileinput
from geocoder.api import options
providers = sorted(options.keys())
methods = ['geocode', 'reverse', 'elevation', 'timezone', 'places']
outputs = ['json', 'osm', 'geojson', 'wkt']
units = ['kilometers', 'miles', 'feet', 'meters']
@click.command()
@click.argument('location', nargs=-1)
@click.option('--provider', '-p', default='osm', type=click.Choice(providers))
@click.option('--method', '-m', default='geocode', type=click.Choice(methods))
@click.option('--output', '-o', default='json', type=click.Choice(outputs))
@click.option('--units', '-u', default='kilometers', type=click.Choice(units))
@click.option('--timeout', '-t', default=5.0)
@click.option('--distance', is_flag=True)
@click.option('--language', default='')
@click.option('--url', default='')
@click.option('--proxies')
@click.option('--key')
# following are for Tamu provider
@click.option('--city', '-c', default='')
@click.option('--state', '-s', default='')
@click.option('--zipcode', '-z', default='')
def cli(location, **kwargs):
"""Geocode an arbitrary number of strings from Command Line."""
locations = []
# Read Standard Input
# $ cat foo.txt | geocode
try:
for line in fileinput.input():
locations.append(line.strip())
except:
pass
# Read multiple files & user input location
for item in location:
if os.path.exists(item):
with open(item, 'rb') as f:
locations += f.read().splitlines()
else:
locations.append(item)
# Distance calculation
if kwargs['distance']:
d = geocoder.distance(locations, **kwargs)
click.echo(d)
return
# Geocode results from user input
for location in locations:
g = geocoder.get(location.strip(), **kwargs)
try:
click.echo(json.dumps(getattr(g, kwargs['output'])))
except IOError:
# When invalid command is entered a broken pipe error occurs
return
if __name__ == '__main__':
cli()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

95
geocoder/distance.py Normal file
View File

@ -0,0 +1,95 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from math import radians, cos, sin, asin, sqrt
from geocoder.location import Location
AVG_EARTH_RADIUS = 6371 # in km
def Distance(*args, **kwargs):
total = 0.0
last = None
if len(args) == 1 and isinstance(args, (list, tuple)):
args = args[0]
if len(args) <= 1:
raise ValueError("Distance needs at least two locations")
for location in args:
if last:
distance = haversine(Location(last), Location(location), **kwargs)
if distance:
total += distance
last = location
return total
def haversine(point1, point2, **kwargs):
""" Calculate the great-circle distance bewteen two points on the Earth surface.
:input: two 2-tuples, containing the latitude and longitude of each point
in decimal degrees.
Example: haversine((45.7597, 4.8422), (48.8567, 2.3508))
:output: Returns the distance bewteen the two points.
The default unit is kilometers. Miles can be returned
if the ``miles`` parameter is set to True.
"""
lookup_units = {
'miles': 'miles',
'mile': 'miles',
'mi': 'miles',
'ml': 'miles',
'kilometers': 'kilometers',
'kilometres': 'kilometers',
'kilometer': 'kilometers',
'kilometre': 'kilometers',
'km': 'kilometers',
'meters': 'meters',
'metres': 'meters',
'meter': 'meters',
'metre': 'meters',
'm': 'meters',
'feet': 'feet',
'f': 'feet',
'ft': 'feet',
}
if point1.ok and point2.ok:
# convert all latitudes/longitudes from decimal degrees to radians
lat1, lng1, lat2, lng2 = list(map(radians, point1.latlng + point2.latlng))
# calculate haversine
lat = lat2 - lat1
lng = lng2 - lng1
d = sin(lat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(lng / 2) ** 2
h = 2 * AVG_EARTH_RADIUS * asin(sqrt(d))
# Measurements
units = kwargs.get('units', 'kilometers').lower()
units_calculation = {
'miles': h * 0.621371,
'feet': h * 0.621371 * 5280,
'meters': h * 1000,
'kilometers': h,
}
if units in lookup_units:
return units_calculation[lookup_units[units]]
else:
raise ValueError("Unknown units of measurement")
else:
print(u'[WARNING] Error calculating the following two locations.\n'
'Points: {0} to {1}'.format(point1.location, point2.location))
if __name__ == '__main__':
d = Distance('Ottawa, ON', 'Toronto, ON', 'Montreal, QC')
print(d)

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

133
geocoder/freegeoip.py Normal file
View File

@ -0,0 +1,133 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
import requests
import ratelim
from geocoder.base import OneResult, MultipleResultsQuery
class FreeGeoIPResult(OneResult):
@property
def lat(self):
return self.raw.get('latitude')
@property
def lng(self):
return self.raw.get('longitude')
@property
def address(self):
if self.city:
return u'{0}, {1} {2}'.format(self.city, self.state, self.country)
elif self.state:
return u'{0}, {1}'.format(self.state, self.country)
elif self.country:
return u'{0}'.format(self.country)
return u''
@property
def postal(self):
zip_code = self.raw.get('zip_code')
postal_code = self.raw.get('postal_code')
if zip_code:
return zip_code
if postal_code:
return postal_code
@property
def city(self):
return self.raw.get('city')
@property
def state(self):
return self.raw.get('region')
@property
def region_code(self):
return self.raw.get('region_code')
@property
def country(self):
return self.raw.get('country_name')
@property
def country_code3(self):
return self.raw.get('country_code3')
@property
def continent(self):
return self.raw.get('continent')
@property
def timezone(self):
return self.raw.get('timezone')
@property
def area_code(self):
return self.raw.get('area_code')
@property
def dma_code(self):
return self.raw.get('dma_code')
@property
def offset(self):
return self.raw.get('offset')
@property
def organization(self):
return self.raw.get('organization')
@property
def ip(self):
return self.raw.get('ip')
@property
def time_zone(self):
return self.raw.get('time_zone')
class FreeGeoIPQuery(MultipleResultsQuery):
"""
FreeGeoIP.net
=============
freegeoip.net provides a public HTTP API for software developers to
search the geolocation of IP addresses. It uses a database of IP addresses
that are associated to cities along with other relevant information like
time zone, latitude and longitude.
You're allowed up to 10,000 queries per hour by default. Once this
limit is reached, all of your requests will result in HTTP 403,
forbidden, until your quota is cleared.
API Reference
-------------
http://freegeoip.net/
"""
provider = 'freegeoip'
method = 'geocode'
_URL = 'https://freegeoip.net/json/'
_RESULT_CLASS = FreeGeoIPResult
_KEY_MANDATORY = False
def _before_initialize(self, location, **kwargs):
self.url += location
@staticmethod
@ratelim.greedy(10000, 60 * 60)
def rate_limited_get(*args, **kwargs):
return requests.get(*args, **kwargs)
def _adapt_results(self, json_response):
return [json_response]
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = FreeGeoIPQuery('99.240.181.199')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

104
geocoder/gaode.py Normal file
View File

@ -0,0 +1,104 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import gaode_key
class GaodeResult(OneResult):
@property
def lat(self):
return float(self.raw.get('location', '0,0').replace("'", '').split(',')[1])
@property
def lng(self):
return float(self.raw.get('location', '0,0').replace("'", '').split(',')[0])
@property
def quality(self):
return self.raw.get('level')
@property
def address(self):
return self.raw.get('formatted_address')
@property
def country(self):
return '中国'
@property
def province(self):
return self.raw.get('province')
@property
def state(self):
return self.raw.get('province')
@property
def city(self):
return self.raw.get('city')
@property
def district(self):
return self.raw.get('district')
@property
def street(self):
return self.raw.get('street')
@property
def adcode(self):
return self.raw.get('adcode')
@property
def housenumber(self):
return self.raw.get('number')
class GaodeQuery(MultipleResultsQuery):
"""
Gaode AMap Geocoding API
===================
Gaode Maps Geocoding API is a free open the API, the default quota
2000 times / day.
Params
------
:param location: Your search location you want geocoded.
:param key: Gaode API key.
References
----------
API Documentation: http://lbs.amap.com/api/webservice/guide/api/georegeo
Get AMap Key: http://lbs.amap.com/dev/
"""
provider = 'gaode'
method = 'geocode'
_URL = 'http://restapi.amap.com/v3/geocode/geo'
_RESULT_CLASS = GaodeResult
_KEY = gaode_key
def _build_params(self, location, provider_key, **kwargs):
return {
'address': location,
'output': 'JSON',
'key': provider_key,
}
def _build_headers(self, provider_key, **kwargs):
return {'Referer': kwargs.get('referer', '')}
def _adapt_results(self, json_response):
return json_response['geocodes']
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = GaodeQuery('将台路')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

106
geocoder/gaode_reverse.py Normal file
View File

@ -0,0 +1,106 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.location import Location
from geocoder.base import OneResult
from geocoder.gaode import GaodeQuery
class GaodeReverseResult(OneResult):
@property
def ok(self):
return bool(self.address)
@property
def address(self):
return self.raw['formatted_address']
@property
def country(self):
return self.raw['addressComponent']['country']
@property
def province(self):
return self.raw['addressComponent']['province']
@property
def state(self):
return self.raw['addressComponent']['province']
@property
def city(self):
if len(self.raw['addressComponent']['city']) == 0:
return self.raw['addressComponent']['province']
else:
return self.raw['addressComponent']['city']
@property
def district(self):
return self.raw['addressComponent']['district']
@property
def street(self):
return self.raw['addressComponent']['streetNumber']['street']
@property
def adcode(self):
return self.raw['addressComponent']['adcode']
@property
def township(self):
return self.raw['addressComponent']['township']
@property
def towncode(self):
return self.raw['addressComponent']['towncode']
@property
def housenumber(self):
return self.raw['addressComponent']['streetNumber']['number']
class GaodeReverse(GaodeQuery):
"""
Gaode GeoReverse API
===================
Gaode Maps GeoReverse API is a free open the API, the default quota
2000 times / day.
Params
------
:param location: Your search location you want geocoded.
:param key: Gaode API key.
:param referer: Gaode API referer website.
References
----------
API Documentation: http://lbs.amap.com/api/webservice/guide/api/georegeo
Get Gaode AMap Key: http://lbs.amap.com/dev/
"""
provider = 'gaode'
method = 'reverse'
_URL = 'http://restapi.amap.com/v3/geocode/regeo'
_RESULT_CLASS = GaodeReverseResult
def _build_params(self, location, provider_key, **kwargs):
location = Location(location)
return {
'location': str(location.lng) + ',' + str(location.lat),
'output': 'json',
'key': provider_key,
}
def _adapt_results(self, json_response):
return [json_response['regeocode']]
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = GaodeReverse("39.971577, 116.506142")
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

202
geocoder/geocodefarm.py Normal file
View File

@ -0,0 +1,202 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import geocodefarm_key
class GeocodeFarmResult(OneResult):
def __init__(self, json_content):
# create safe shortcuts
self._coordinates = json_content.get('COORDINATES', {})
self._boundaries = json_content.get('BOUNDARIES', {})
self._address = json_content.get('ADDRESS', {})
self._location_details = json_content.get('LOCATION_DETAILS', {})
# proceed with super.__init__
super(GeocodeFarmResult, self).__init__(json_content)
@property
def lat(self):
lat = self._coordinates.get('latitude')
if lat:
return float(lat)
@property
def lng(self):
lng = self._coordinates.get('longitude')
if lng:
return float(lng)
@property
def accuracy(self):
return self.raw.get('accuracy')
@property
def bbox(self):
south = self._boundaries.get('southwest_latitude')
west = self._boundaries.get('southwest_longitude')
north = self._boundaries.get('northeast_latitude')
east = self._boundaries.get('northeast_longitude')
return self._get_bbox(south, west, north, east)
@property
def address(self):
return self.raw.get('formatted_address')
@property
def housenumber(self):
return self._address.get('street_number')
@property
def street(self):
return self._address.get('street_name')
@property
def neighborhood(self):
return self._address.get('neighborhood')
@property
def city(self):
return self._address.get('locality')
@property
def county(self):
return self._address.get('admin_2')
@property
def state(self):
return self._address.get('admin_1')
@property
def country(self):
return self._address.get('country')
@property
def postal(self):
return self._address.get('postal_code')
@property
def elevation(self):
return self._location_details.get('elevation')
@property
def timezone_long(self):
return self._location_details.get('timezone_long')
@property
def timezone_short(self):
return self._location_details.get('timezone_short')
class GeocodeFarmQuery(MultipleResultsQuery):
"""
Geocode.Farm
============
Geocode.Farm is one of the few providers that provide this highly
specialized service for free. We also have affordable paid plans, of
course, but our free services are of the same quality and provide the same
results. The major difference between our affordable paid plans and our
free API service is the limitations. On one of our affordable paid plans
your limit is set based on the plan you signed up for, starting at 25,000
query requests per day (API calls). On our free API offering, you are
limited to 250 query requests per day (API calls).
Params
------
:param location: The string to search for. Usually a street address.
:param key: (optional) API Key. Only Required for Paid Users.
:param lang: (optional) 2 digit lanuage code to return results in. Currently only "en"(English) or "de"(German) supported.
:param country: (optional) The country to return results in. Used for biasing purposes and may not fully filter results to this specific country.
API Reference
-------------
https://geocode.farm/geocoding/free-api-documentation/
"""
provider = 'geocodefarm'
method = 'geocode'
_URL = 'https://www.geocode.farm/v3/json/forward/'
_RESULT_CLASS = GeocodeFarmResult
_KEY = geocodefarm_key
_KEY_MANDATORY = False
def __init__(self, location, **kwargs):
super(GeocodeFarmQuery, self).__init__(location, **kwargs)
self.api_status = {}
self.api_account = {}
def _build_params(self, location, provider_key, **kwargs):
return {
'addr': location,
'key': provider_key,
'lang': kwargs.get('lang', ''),
'country': kwargs.get('country', ''),
'count': kwargs.get('maxRows', 1),
}
def _catch_errors(self, json_response):
status = json_response['geocoding_results']['STATUS'].get('status')
if not status == 'SUCCESS':
self.error = status
return self.error
def _adapt_results(self, json_response):
return json_response['geocoding_results']['RESULTS']
def _parse_results(self, json_response):
super(GeocodeFarmQuery, self)._parse_results(json_response)
# store status and account details
self.api_status = json_response['geocoding_results']['STATUS']
self.api_account = json_response['geocoding_results']['ACCOUNT']
@property
def access(self):
return self.api_status.get('access')
@property
def address_provided(self):
return self.api_status.get('address_provided')
@property
def ip_address(self):
return self.api_account.get('ip_address')
@property
def distribution_license(self):
return self.api_account.get('distribution_license')
@property
def usage_limit(self):
usage_limit = self.api_account.get('usage_limit')
if usage_limit:
return int(usage_limit)
@property
def used_today(self):
used_today = self.api_account.get('used_today')
if used_today:
return int(used_today)
@property
def used_total(self):
used_total = self.api_account.get('used_total')
if used_total:
return int(used_total)
@property
def first_used(self):
return self.api_account.get('first_used')
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = GeocodeFarmQuery("New York City")
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,55 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.location import Location
from geocoder.geocodefarm import GeocodeFarmQuery
class GeocodeFarmReverse(GeocodeFarmQuery):
"""
Geocode.Farm
=======================
Geocode.Farm is one of the few providers that provide this highly
specialized service for free. We also have affordable paid plans, of
course, but our free services are of the same quality and provide the same
results. The major difference between our affordable paid plans and our
free API service is the limitations. On one of our affordable paid plans
your limit is set based on the plan you signed up for, starting at 25,000
query requests per day (API calls). On our free API offering, you are
limited to 250 query requests per day (API calls).
Params
------
:param lat: The numerical latitude value for which you wish to obtain the closest, human-readable address.
:param lon: The numerical longitude value for which you wish to obtain the closest, human-readable address.
:param key: (optional) API Key. Only Required for Paid Users.
:param lang: (optional) 2 digit lanuage code to return results in. Currently only "en"(English) or "de"(German) supported.
:param country: (optional) The country to return results in. Used for biasing purposes and may not fully filter results to this specific country.
API Reference
-------------
https://geocode.farm/geocoding/free-api-documentation/
"""
provider = 'geocodefarm'
method = 'reverse'
_URL = 'https://www.geocode.farm/v3/json/reverse/'
def _build_params(self, location, provider_key, **kwargs):
location = Location(location)
return {
'lat': location.latitude,
'lon': location.longitude,
'key': provider_key,
'lang': kwargs.get('lang', ''),
'country': kwargs.get('country', ''),
}
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = GeocodeFarmReverse([45.3, -75.4])
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

98
geocoder/geolytica.py Normal file
View File

@ -0,0 +1,98 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.base import OneResult, MultipleResultsQuery
class GeolyticaResult(OneResult):
def __init__(self, json_content):
# create safe shortcuts
self._standard = json_content.get('standard', {})
# proceed with super.__init__
super(GeolyticaResult, self).__init__(json_content)
@property
def lat(self):
lat = self.raw.get('latt', '').strip()
if lat:
return float(lat)
@property
def lng(self):
lng = self.raw.get('longt', '').strip()
if lng:
return float(lng)
@property
def postal(self):
return self.raw.get('postal', '').strip()
@property
def housenumber(self):
return self._standard.get('stnumber', '').strip()
@property
def street(self):
return self._standard.get('staddress', '').strip()
@property
def city(self):
return self._standard.get('city', '').strip()
@property
def state(self):
return self._standard.get('prov', '').strip()
@property
def address(self):
if self.street_number:
return u'{0} {1}, {2}'.format(self.street_number, self.route, self.locality)
elif self.route and self.route != 'un-known':
return u'{0}, {1}'.format(self.route, self.locality)
else:
return self.locality
class GeolyticaQuery(MultipleResultsQuery):
"""
Geocoder.ca
===========
A Canadian and US location geocoder.
API Reference
-------------
http://geocoder.ca/?api=1
"""
provider = 'geolytica'
method = 'geocode'
_URL = 'http://geocoder.ca'
_RESULT_CLASS = GeolyticaResult
_KEY_MANDATORY = False
def _build_params(self, location, provider_key, **kwargs):
params = {
'json': 1,
'locate': location,
'geoit': 'xml'
}
if 'strictmode' in kwargs:
params.update({'strictmode': kwargs.pop('strictmode')})
if 'strict' in kwargs:
params.update({'strict': kwargs.pop('strict')})
if 'auth' in kwargs:
params.update({'auth': kwargs.pop('auth')})
return params
def _adapt_results(self, json_response):
return [json_response]
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = GeolyticaQuery('1552 Payette dr., Ottawa')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

151
geocoder/geonames.py Normal file
View File

@ -0,0 +1,151 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import json
import logging
from geocoder.base import MultipleResultsQuery, OneResult
from geocoder.keys import geonames_username
from geocoder.location import BBox
LOGGER = logging.getLogger(__name__)
class GeonamesResult(OneResult):
@property
def lat(self):
return self.raw.get('lat')
@property
def lng(self):
return self.raw.get('lng')
@property
def geonames_id(self):
return self.raw.get('geonameId')
@property
def address(self):
return self.raw.get('name')
@property
def feature_class(self):
return self.raw.get('fcl')
@property
def class_description(self):
return self.raw.get('fclName')
@property
def code(self):
return self.raw.get('fcode')
@property
def description(self):
return self.raw.get('fcodeName')
@property
def state(self):
return self.raw.get('adminName1')
@property
def state_code(self):
return self.raw.get('adminCode1')
@property
def country(self):
return self.raw.get('countryName')
@property
def country_code(self):
return self.raw.get('countryCode')
@property
def population(self):
return self.raw.get('population')
class GeonamesQuery(MultipleResultsQuery):
"""
GeoNames REST Web Services
==========================
GeoNames is mainly using REST webservices. Find nearby postal codes / reverse geocoding
This service comes in two flavors.You can either pass the lat/long or a postalcode/placename.
API Reference
-------------
http://www.geonames.org/export/web-services.html
"""
provider = 'geonames'
method = 'geocode'
_URL = 'http://api.geonames.org/searchJSON'
_RESULT_CLASS = GeonamesResult
_KEY = geonames_username
def _build_params(self, location, provider_key, **kwargs):
"""Will be overridden according to the targetted web service"""
base_kwargs = {
'q': location,
'fuzzy': kwargs.get('fuzzy', 1.0),
'username': provider_key,
'maxRows': kwargs.get('maxRows', 1),
}
# check out for bbox in kwargs
bbox = kwargs.pop('proximity', None)
if bbox is not None:
bbox = BBox.factory(bbox)
base_kwargs.update(
{'east': bbox.east, 'west': bbox.west,
'north': bbox.north, 'south': bbox.south})
# look out for valid extra kwargs
supported_kwargs = set((
'name', 'name_equals', 'name_startsWith', 'startRow',
'country', 'countryBias', 'continentCode',
'adminCode1', 'adminCode2', 'adminCode3', 'cities',
'featureClass', 'featureCode',
'lang', 'type', 'style',
'isNameRequired', 'tag', 'operator', 'charset',
'east', 'west', 'north', 'south',
'orderby', 'inclBbox',
))
found_kwargs = supported_kwargs & set(kwargs.keys())
LOGGER.debug("Adding extra kwargs %s", found_kwargs)
# update base kwargs with extra ones
base_kwargs.update(dict(
[(extra, kwargs[extra]) for extra in found_kwargs]
))
return base_kwargs
def _catch_errors(self, json_response):
""" Changed: removed check on number of elements:
- totalResultsCount not sytematically returned (e.g in hierarchy)
- done in base.py
"""
status = json_response.get('status')
if status:
message = status.get('message')
value = status.get('value')
custom_messages = {
10: 'Invalid credentials',
18: 'Do not use the demo account for your application',
}
self.error = custom_messages.get(value, message)
LOGGER.error("Error %s from JSON %s", self.error, json_response)
return self.error
def _adapt_results(self, json_response):
# extract the array of JSON objects
return json_response['geonames']
if __name__ == '__main__':
g = GeonamesQuery('Ottawa, Ontario', maxRows=1)
print(json.dumps(g.geojson, indent=4))
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,30 @@
from __future__ import absolute_import
from geocoder.geonames import GeonamesQuery
class GeonamesChildren(GeonamesQuery):
""" Children:
http://api.geonames.org/childrenJSON?formatted=true&geonameId=6094817
"""
provider = 'geonames'
method = 'children'
_URL = 'http://api.geonames.org/childrenJSON'
def _build_params(self, location, provider_key, **kwargs):
"""Will be overridden according to the targetted web service"""
return {
'geonameId': location,
'username': provider_key,
}
if __name__ == '__main__':
print("Searching Ottawa...")
g = GeonamesQuery('Ottawa, Ontario')
g.debug()
print("Searching its children...")
c = GeonamesChildren(g.pop().geonames_id)
c.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,122 @@
from __future__ import absolute_import
from geocoder.geonames import GeonamesQuery, GeonamesResult
class GeonamesFullResult(GeonamesResult):
""" Get more information for given geonames_id, e.g timzone and administrative hierarchy"""
@property
def continent(self):
return self.raw.get('continentCode', "")
@property
def country_geonames_id(self):
return self.raw.get('countryId', 0)
@property
def state_geonames_id(self):
return self.raw.get('adminId1', 0)
@property
def admin2(self):
return self.raw.get('adminName2', "")
@property
def admin2_geonames_id(self):
return self.raw.get('adminId2', "")
@property
def admin3(self):
return self.raw.get('adminName3', "")
@property
def admin3_geonames_id(self):
return self.raw.get('adminId3', "")
@property
def admin4(self):
return self.raw.get('adminName4', "")
@property
def admin4_geonames_id(self):
return self.raw.get('adminId4', "")
@property
def admin5(self):
return self.raw.get('adminName5', "")
@property
def admin5_geonames_id(self):
return self.raw.get('adminId5', "")
@property
def srtm3(self):
return self.raw.get('srtm3', 0)
@property
def wikipedia(self):
return self.raw.get('wikipediaURL', "")
@property
def timeZoneId(self):
timezone = self.raw.get('timezone')
if timezone:
return timezone.get('timeZoneId')
@property
def timeZoneName(self):
timezone = self.raw.get('timezone')
if timezone:
return timezone.get('timeZoneId')
@property
def rawOffset(self):
timezone = self.raw.get('timezone')
if timezone:
return timezone.get('gmtOffset')
@property
def dstOffset(self):
timezone = self.raw.get('timezone')
if timezone:
return timezone.get('dstOffset')
@property
def bbox(self):
bbox = self.raw.get('bbox', {})
south = bbox.get('south')
west = bbox.get('west')
north = bbox.get('north')
east = bbox.get('east')
return self._get_bbox(south, west, north, east)
class GeonamesDetails(GeonamesQuery):
""" Details:
http://api.geonames.org/getJSON?geonameId=6094817&style=full
"""
provider = 'geonames'
method = 'details'
_URL = 'http://api.geonames.org/getJSON'
_RESULT_CLASS = GeonamesFullResult
def _build_params(self, location, provider_key, **kwargs):
"""Will be overridden according to the targetted web service"""
return {
'geonameId': location,
'username': provider_key,
'style': 'full'
}
def _adapt_results(self, json_response):
# the returned JSON contains the object.
# Need to wrap it into an array
return [json_response]
if __name__ == '__main__':
c = GeonamesDetails(6094817)
c.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,20 @@
from __future__ import absolute_import
from geocoder.geonames_children import GeonamesChildren
class GeonamesHierarchy(GeonamesChildren):
""" Hierarchy:
http://api.geonames.org/hierarchyJSON?formatted=true&geonameId=6094817
"""
provider = 'geonames'
method = 'hierarchy'
_URL = 'http://api.geonames.org/hierarchyJSON'
if __name__ == '__main__':
print("Searching Ottawa's hierarchy...")
c = GeonamesHierarchy(6094817)
c.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

85
geocoder/gisgraphy.py Normal file
View File

@ -0,0 +1,85 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.base import OneResult, MultipleResultsQuery
class GisgraphyResult(OneResult):
@property
def lat(self):
return self.raw.get('lat')
@property
def lng(self):
return self.raw.get('lng')
@property
def address(self):
return self.raw.get('formatedFull', '')
@property
def country(self):
return self.raw.get('countryCode', '')
@property
def state(self):
return self.raw.get('state', '')
@property
def city(self):
return self.raw.get('city', '')
@property
def street(self):
return self.raw.get('streetName', '')
@property
def housenumber(self):
return self.raw.get('houseNumber', '')
@property
def postal(self):
return self.raw.get('zipCode', '')
class GisgraphyQuery(MultipleResultsQuery):
"""
Gisgraphy REST API
=======================
API Reference
-------------
http://www.gisgraphy.com/documentation/user-guide.php
"""
provider = 'gisgraphy'
method = 'geocode'
_URL = 'https://services.gisgraphy.com/geocoding/'
_RESULT_CLASS = GisgraphyResult
_KEY_MANDATORY = False
def _build_headers(self, provider_key, **kwargs):
return {
'Referer': "https://services.gisgraphy.com",
'User-agent': 'geocoder-converter'
}
def _build_params(self, location, provider_key, **kwargs):
return {
'address': location,
'limitnbresult': kwargs.get('maxRows', 1),
'format': 'json',
}
def _adapt_results(self, json_response):
return json_response['result']
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = GisgraphyQuery('Ottawa Ontario', maxRows=3)
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,46 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.location import Location
from geocoder.gisgraphy import GisgraphyResult, GisgraphyQuery
class GisgraphyReverseResult(GisgraphyResult):
@property
def ok(self):
return bool(self.address)
class GisgraphyReverse(GisgraphyQuery):
"""
Gisgraphy REST API
=======================
API Reference
-------------
http://www.gisgraphy.com/documentation/user-guide.php
"""
provider = 'gisgraphy'
method = 'reverse'
_URL = 'https://services.gisgraphy.com/reversegeocoding/'
_RESULT_CLASS = GisgraphyReverseResult
def _build_params(self, location, provider_key, **kwargs):
location = Location(location)
return {
'lat': location.lat,
'lng': location.lng,
'format': 'json',
}
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = GisgraphyReverse("45.4 -75.7")
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

294
geocoder/google.py Normal file
View File

@ -0,0 +1,294 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import six
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import google_key, google_client, google_client_secret
from collections import OrderedDict
import ratelim
class GoogleResult(OneResult):
def __init__(self, json_content):
# flatten geometry
geometry = json_content.get('geometry', {})
self._location = geometry.get('location', {})
self._location_type = geometry.get('location_type', {})
self._viewport = geometry.get('viewport', {})
# Parse address components with short & long names
for item in json_content['address_components']:
for category in item['types']:
json_content.setdefault(category, {})
json_content[category]['long_name'] = item['long_name']
json_content[category]['short_name'] = item['short_name']
# proceed with super.__init__
super(GoogleResult, self).__init__(json_content)
@property
def lat(self):
return self._location.get('lat')
@property
def lng(self):
return self._location.get('lng')
@property
def place(self):
return self.raw.get('place_id')
@property
def quality(self):
quality = self.raw.get('types')
if quality:
return quality[0]
@property
def accuracy(self):
return self._location_type
@property
def bbox(self):
south = self._viewport.get('southwest', {}).get('lat')
west = self._viewport.get('southwest', {}).get('lng')
north = self._viewport.get('northeast', {}).get('lat')
east = self._viewport.get('northeast', {}).get('lng')
return self._get_bbox(south, west, north, east)
@property
def address(self):
return self.raw.get('formatted_address')
@property
def postal(self):
return self.raw.get('postal_code', {}).get('short_name')
@property
def subpremise(self):
return self.raw.get('subpremise', {}).get('short_name')
@property
def housenumber(self):
return self.raw.get('street_number', {}).get('short_name')
@property
def street(self):
return self.raw.get('route', {}).get('short_name')
@property
def street_long(self):
return self.raw.get('route', {}).get('long_name')
@property
def road_long(self):
return self.street_long
@property
def neighborhood(self):
return self.raw.get('neighborhood', {}).get('short_name')
@property
def sublocality(self):
return self.raw.get('sublocality', {}).get('short_name')
@property
def city(self):
return self.raw.get('locality', {}).get('short_name') or self.postal_town
@property
def city_long(self):
return self.raw.get('locality', {}).get('long_name') or self.postal_town_long
@property
def postal_town(self):
return self.raw.get('postal_town', {}).get('short_name')
@property
def postal_town_long(self):
return self.raw.get('postal_town', {}).get('long_name')
@property
def county(self):
return self.raw.get('administrative_area_level_2', {}).get('short_name')
@property
def state(self):
return self.raw.get('administrative_area_level_1', {}).get('short_name')
@property
def state_long(self):
return self.raw.get('administrative_area_level_1', {}).get('long_name')
@property
def province_long(self):
return self.state_long
@property
def country(self):
return self.raw.get('country', {}).get('short_name')
@property
def country_long(self):
return self.raw.get('country', {}).get('long_name')
class GoogleQuery(MultipleResultsQuery):
"""
Google Geocoding API
====================
Geocoding is the process of converting addresses into geographic
coordinates (like latitude 37.423021 and longitude -122.083739),
which you can use to place markers or position the map.
API Reference
-------------
https://developers.google.com/maps/documentation/geocoding
For ambiguous queries or 'nearby' type queries, use the Places Text Search instead.
https://developers.google.com/maps/documentation/geocoding/best-practices#automated-system
Parameters
----------
:param location: Your search location you want geocoded.
:param components: Component Filtering
:param method: (default=geocode) Use the following:
> geocode
> places
> reverse
> timezone
> elevation
:param key: Your Google developers free key.
:param language: 2-letter code of preferred language of returned address elements.
:param client: Google for Work client ID. Use with client_secret. Cannot use with key parameter
:param client_secret: Google for Work client secret. Use with client.
"""
provider = 'google'
method = 'geocode'
_URL = 'https://maps.googleapis.com/maps/api/geocode/json'
_RESULT_CLASS = GoogleResult
_KEY = google_key
_KEY_MANDATORY = False
def _build_params(self, location, provider_key, **kwargs):
params = self._location_init(location, **kwargs)
params['language'] = kwargs.get('language', '')
self.rate_limit = kwargs.get('rate_limit', True)
# adapt params to authentication method
# either with client / secret
self.client = kwargs.get('client', google_client)
self.client_secret = kwargs.get('client_secret', google_client_secret)
if self.client and self.client_secret:
params['client'] = self.client
return self._encode_params(params)
# or API key
else:
# provider_key is computed in base.py:
# either cls._KEY (google_key) or kwargs['key'] if provided
params['key'] = provider_key
return params
def _location_init(self, location, **kwargs):
return {
'address': location,
'bounds': kwargs.get('bounds', ''),
'components': kwargs.get('components', ''),
'region': kwargs.get('region', ''),
}
def _encode_params(self, params):
# turn non-empty params into sorted list in order to maintain signature validity.
# Requests will honor the order.
ordered_params = sorted([(k, v)
for (k, v) in params.items() if v])
params = OrderedDict(ordered_params)
# the signature parameter needs to come in the end of the url
params['signature'] = self._sign_url(
self.url, ordered_params, self.client_secret)
return params
def _sign_url(self, base_url=None, params=None, client_secret=None):
""" Sign a request URL with a Crypto Key.
Usage:
from urlsigner import sign_url
signed_url = sign_url(base_url=my_url,
params=url_params,
client_secret=CLIENT_SECRET)
Args:
base_url - The trunk of the URL to sign. E.g. https://maps.googleapis.com/maps/api/geocode/json
params - List of tuples of URL parameters INCLUDING YOUR CLIENT ID ('client','gme-...')
client_secret - Your Crypto Key from Google for Work
Returns:
The signature as a dictionary #signed request URL
"""
import hashlib
import hmac
import base64
if six.PY3:
from urllib.parse import urlparse, urlencode
else:
from urllib import urlencode
from urlparse import urlparse
# Return if any parameters aren't given
if not base_url or not self.client_secret or not self.client:
return None
# assuming parameters will be submitted to Requests in identical order!
url = urlparse(base_url + "?" + urlencode(params))
# We only need to sign the path+query part of the string
url_to_sign = (url.path + "?" + url.query).encode('utf-8')
# Decode the private key into its binary format
# We need to decode the URL-encoded private key
decoded_key = base64.urlsafe_b64decode(client_secret)
# Create a signature using the private key and the URL-encoded
# string using HMAC SHA1. This signature will be binary.
signature = hmac.new(decoded_key, url_to_sign, hashlib.sha1)
# Encode the binary signature into base64 for use within a URL
encoded_signature = base64.urlsafe_b64encode(signature.digest())
# Return signature (to be appended as a 'signature' in params)
return encoded_signature
def rate_limited_get(self, *args, **kwargs):
if not self.rate_limit:
return super(GoogleQuery, self).rate_limited_get(*args, **kwargs)
elif self.client and self.client_secret:
return self.rate_limited_get_for_work(*args, **kwargs)
else:
return self.rate_limited_get_for_dev(*args, **kwargs)
@ratelim.greedy(2500, 60 * 60 * 24)
@ratelim.greedy(10, 1)
def rate_limited_get_for_dev(self, *args, **kwargs):
return super(GoogleQuery, self).rate_limited_get(*args, **kwargs)
@ratelim.greedy(100000, 60 * 60 * 24) # Google for Work daily limit
@ratelim.greedy(50, 1) # Google for Work limit per second
def rate_limited_get_for_work(self, *args, **kwargs):
return super(GoogleQuery, self).rate_limited_get(*args, **kwargs)
def _catch_errors(self, json_response):
status = json_response.get('status')
if not status == 'OK':
self.error = status
return self.error
def _adapt_results(self, json_response):
return json_response.get('results', [])
if __name__ == '__main__':
g = GoogleQuery('11 Wall Street, New York')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,74 @@
#!/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 Location
class ElevationResult(OneResult):
@property
def status(self):
if self.elevation:
return 'OK'
else:
return 'ERROR - No Elevation found'
@property
def ok(self):
return bool(self.elevation)
@property
def meters(self):
if self.elevation:
return round(self.elevation, 1)
@property
def feet(self):
if self.elevation:
return round(self.elevation * 3.28084, 1)
@property
def elevation(self):
return self.raw.get('elevation')
@property
def resolution(self):
return self.raw.get('resolution')
class ElevationQuery(MultipleResultsQuery):
"""
Google Elevation API
====================
The Elevation API provides elevation data for all locations on the surface of the
earth, including depth locations on the ocean floor (which return negative values).
In those cases where Google does not possess exact elevation measurements at the
precise location you request, the service will interpolate and return an averaged
value using the four nearest locations.
API Reference
-------------
https://developers.google.com/maps/documentation/elevation/
"""
provider = 'google'
method = 'elevation'
_URL = 'https://maps.googleapis.com/maps/api/elevation/json'
_RESULT_CLASS = ElevationResult
_KEY = google_key
def _build_params(self, location, provider_key, **kwargs):
return {
'locations': str(Location(location)),
}
def _adapt_results(self, json_response):
return json_response['results']
if __name__ == '__main__':
g = ElevationQuery([45.123, -76.123])
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

181
geocoder/google_places.py Normal file
View File

@ -0,0 +1,181 @@
#!/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()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,41 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.google import GoogleResult, GoogleQuery
from geocoder.location import Location
class GoogleReverseResult(GoogleResult):
@property
def ok(self):
return bool(self.address)
class GoogleReverse(GoogleQuery):
"""
Google Geocoding API
====================
Geocoding is the process of converting addresses (like "1600 Amphitheatre
Parkway, Mountain View, CA") into geographic coordinates (like latitude
37.423021 and longitude -122.083739), which you can use to place markers or
position the map.
API Reference
-------------
https://developers.google.com/maps/documentation/geocoding/
"""
provider = 'google'
method = 'reverse'
def _location_init(self, location, **kwargs):
return {
'latlng': str(Location(location)),
'sensor': 'false',
}
if __name__ == '__main__':
g = GoogleReverse((45.4215296, -75.6971930))
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,68 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import time
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import google_key
from geocoder.location import Location
class TimezoneResult(OneResult):
def __repr__(self):
return u'<[{}] [{}]>'.format(self.status, self.timeZoneName)
@property
def ok(self):
return bool(self.timeZoneName)
@property
def timeZoneId(self):
return self.raw.get('timeZoneId')
@property
def timeZoneName(self):
return self.raw.get('timeZoneName')
@property
def rawOffset(self):
return self.raw.get('rawOffset')
@property
def dstOffset(self):
return self.raw.get('dstOffset')
class TimezoneQuery(MultipleResultsQuery):
"""
Google Time Zone API
====================
The Time Zone API provides time offset data for locations on the surface of the earth.
Requesting the time zone information for a specific Latitude/Longitude pair will
return the name of that time zone, the time offset from UTC, and the Daylight Savings offset.
API Reference
-------------
https://developers.google.com/maps/documentation/timezone/
"""
provider = 'google'
method = 'timezone'
_URL = 'https://maps.googleapis.com/maps/api/timezone/json'
_RESULT_CLASS = TimezoneResult
_KEY = google_key
def _build_params(self, location, provider_key, **kwargs):
return {
'location': str(Location(location)),
'timestamp': kwargs.get('timestamp', time.time()),
}
def _adapt_results(self, json_response):
return [json_response]
if __name__ == '__main__':
g = TimezoneQuery([45.5375801, -75.2465979])
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

166
geocoder/here.py Normal file
View File

@ -0,0 +1,166 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import here_app_id, here_app_code
from geocoder.location import BBox
class HereResult(OneResult):
def __init__(self, json_content):
self._display_position = json_content.get('DisplayPosition', {})
self._address = json_content.get('Address', {})
self._mapview = json_content.get('MapView', {})
for item in json_content['Address']['AdditionalData']:
json_content[item['key']] = item['value']
super(HereResult, self).__init__(json_content)
@property
def lat(self):
return self._display_position.get('Latitude')
@property
def lng(self):
return self._display_position.get('Longitude')
@property
def address(self):
return self._address.get('Label')
@property
def postal(self):
return self._address.get('PostalCode')
@property
def housenumber(self):
return self._address.get('HouseNumber')
@property
def street(self):
return self._address.get('Street')
@property
def neighborhood(self):
return self.district
@property
def district(self):
return self._address.get('District')
@property
def city(self):
return self._address.get('City')
@property
def county(self):
return self._address.get('County')
@property
def state(self):
return self._address.get('State')
@property
def country(self):
return self._address.get('Country')
@property
def quality(self):
return self.raw.get('MatchLevel')
@property
def accuracy(self):
return self.raw.get('MatchType')
@property
def bbox(self):
south = self._mapview['BottomRight'].get('Latitude')
north = self._mapview['TopLeft'].get('Latitude')
west = self._mapview['TopLeft'].get('Longitude')
east = self._mapview['BottomRight'].get('Longitude')
return self._get_bbox(south, west, north, east)
class HereQuery(MultipleResultsQuery):
"""
HERE Geocoding REST API
=======================
Send a request to the geocode endpoint to find an address
using a combination of country, state, county, city,
postal code, district, street and house number.
API Reference
-------------
https://developer.here.com/rest-apis/documentation/geocoder
"""
provider = 'here'
method = 'geocode'
qualified_address = ['city', 'district', 'postal', 'state', 'country']
_URL = 'http://geocoder.cit.api.here.com/6.2/geocode.json'
_RESULT_CLASS = HereResult
@classmethod
def _get_api_key(cls, key=None):
# API key is split between app_id and app_code -> managed in _build_params
pass
def _build_params(self, location, provider_key, **kwargs):
# HERE Credentials
app_id = kwargs.get('app_id', here_app_id)
app_code = kwargs.get('app_code', here_app_code)
if not bool(app_id and app_code):
raise ValueError("Provide app_id & app_code")
# URL Params
params = {
'searchtext': location,
'app_id': app_id,
'app_code': app_code,
'gen': 9,
'maxresults': kwargs.get('maxRows', 1),
'language': kwargs.get('language', 'en'),
}
# bounding box if present
bbox = kwargs.get('bbox')
if bbox:
bbox = BBox(bbox=bbox)
# do not forget to convert bbox to mapbox expectations...
params['bbox'] = u'{north},{west};{south},{east}'.format(
west=bbox.west,
east=bbox.east,
south=bbox.south,
north=bbox.north
)
for value in self.qualified_address:
if kwargs.get(value) is not None:
params[value] = kwargs.get(value)
return params
def _catch_errors(self, json_response):
status = json_response.get('type')
if not status == 'OK':
self.error = status
return self.error
def _adapt_results(self, json_response):
# Build intial Tree with results
return [item['Location']
for item in json_response['Response']['View'][0]['Result']]
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = HereQuery("New York City")
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

50
geocoder/here_reverse.py Normal file
View File

@ -0,0 +1,50 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.location import Location
from geocoder.here import HereResult, HereQuery
class HereReverseResult(HereResult):
@property
def ok(self):
return bool(self.address)
class HereReverse(HereQuery):
"""
HERE Geocoding REST API
=======================
Send a request to the geocode endpoint to find an address
using a combination of country, state, county, city,
postal code, district, street and house number.
API Reference
-------------
https://developer.here.com/rest-apis/documentation/geocoder
"""
provider = 'here'
method = 'reverse'
_RESULT_CLASS = HereReverseResult
_URL = 'http://reverse.geocoder.cit.api.here.com/6.2/reversegeocode.json'
def _build_params(self, location, provider_key, **kwargs):
params = super(HereReverse, self)._build_params(location, provider_key, **kwargs)
del params['searchtext']
location = str(Location(location))
params.update({
'prox': location,
'mode': 'retrieveAddresses',
'gen': 8,
})
return params
if __name__ == '__main__':
g = HereReverse([45.4049053, -75.7077965])
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

92
geocoder/ipinfo.py Normal file
View File

@ -0,0 +1,92 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.location import Location
class IpinfoResult(OneResult):
@property
def lat(self):
loc = self.raw.get('loc')
if loc:
return Location(loc).lat
@property
def lng(self):
loc = self.raw.get('loc')
if loc:
return Location(loc).lng
@property
def address(self):
if self.city:
return u'{0}, {1}, {2}'.format(self.city, self.state, self.country)
elif self.state:
return u'{0}, {1}'.format(self.state, self.country)
elif self.country:
return u'{0}'.format(self.country)
else:
return u''
@property
def postal(self):
return self.raw.get('postal')
@property
def city(self):
return self.raw.get('city')
@property
def state(self):
return self.raw.get('region')
@property
def country(self):
return self.raw.get('country')
@property
def hostname(self):
return self.raw.get('hostname')
@property
def ip(self):
return self.raw.get('ip')
@property
def org(self):
return self.raw.get('org')
class IpinfoQuery(MultipleResultsQuery):
"""
API Reference
-------------
https://ipinfo.io
"""
provider = 'ipinfo'
method = 'geocode'
_URL = 'http://ipinfo.io/json'
_RESULT_CLASS = IpinfoResult
_KEY_MANDATORY = False
def _before_initialize(self, location, **kwargs):
if location.lower() == 'me' or location == '':
self.url = 'http://ipinfo.io/json'
else:
self.url = 'http://ipinfo.io/{0}/json'.format(self.location)
def _adapt_results(self, json_response):
return [json_response]
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = IpinfoQuery('8.8.8.8')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

65
geocoder/keys.py Normal file
View File

@ -0,0 +1,65 @@
#!/usr/bin/python
# coding: utf8
import os
import re
import requests
bing_key = os.environ.get('BING_API_KEY')
tomtom_key = os.environ.get('TOMTOM_API_KEY')
here_app_id = os.environ.get('HERE_APP_ID')
here_app_code = os.environ.get('HERE_APP_CODE')
geonames_username = os.environ.get('GEONAMES_USERNAME')
opencage_key = os.environ.get('OPENCAGE_API_KEY')
mapquest_key = os.environ.get('MAPQUEST_API_KEY')
baidu_key = os.environ.get('BAIDU_API_KEY')
baidu_security_key = os.environ.get('BAIDU_SECURITY_KEY')
gaode_key = os.environ.get('GAODE_API_KEY')
w3w_key = os.environ.get('W3W_API_KEY')
mapbox_access_token = os.environ.get('MAPBOX_ACCESS_TOKEN')
google_key = os.environ.get('GOOGLE_API_KEY')
google_client = os.environ.get('GOOGLE_CLIENT')
google_client_secret = os.environ.get('GOOGLE_CLIENT_SECRET')
mapzen_key = os.environ.get('MAPZEN_API_KEY')
tamu_key = os.environ.get('TAMU_API_KEY')
geocodefarm_key = os.environ.get('GEOCODEFARM_API_KEY')
tgos_key = os.environ.get('TGOS_API_KEY')
locationiq_key = os.environ.get('LOCATIONIQ_API_KEY')
class CanadapostKeyLazySingleton(object):
CANADAPOST_KEY_REGEX = re.compile(r"'(....-....-....-....)';")
def __init__(self):
self._key = None
def __call__(self, **kwargs):
if self._key is None:
self._key = self.retrieve_key(**kwargs)
return self._key
@classmethod
def retrieve_key(cls, **kwargs):
# get key with traditionnal mechanism
key = kwargs.get('key')
canadapost_key = os.environ.get('CANADAPOST_API_KEY')
if key or canadapost_key:
return key if key else canadapost_key
# fallback
try:
url = 'http://www.canadapost.ca/cpo/mc/personal/postalcode/fpc.jsf'
timeout = kwargs.get('timeout', 5.0)
proxies = kwargs.get('proxies', '')
r = requests.get(url, timeout=timeout, proxies=proxies)
match = cls.CANADAPOST_KEY_REGEX.search(r.text)
if match:
return match.group(1)
else:
raise ValueError('No API Key found')
except Exception as err:
raise ValueError('Could not retrieve API Key: %s' % err)
canadapost_key_getter = CanadapostKeyLazySingleton()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

136
geocoder/komoot.py Normal file
View File

@ -0,0 +1,136 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.location import BBox
from geocoder.base import OneResult, MultipleResultsQuery
class KomootResult(OneResult):
def __init__(self, json_content):
# create safe shortcuts
self._geometry = json_content.get('geometry', {})
self._properties = json_content.get('properties', {})
# proceed with super.__init__
super(KomootResult, self).__init__(json_content)
@property
def lat(self):
return self._geometry['coordinates'][1]
@property
def lng(self):
return self._geometry['coordinates'][0]
@property
def bbox(self):
extent = self._properties.get('extent')
if extent and all(extent):
west = extent[0]
north = extent[1]
east = extent[2]
south = extent[3]
return BBox.factory([south, west, north, east]).as_dict
@property
def address(self):
# Ontario, Canada
address = ', '.join([self.state, self.country])
# 453 Booth street, Ottawa ON, Canada
if self.housenumber:
middle = ', '.join([self.street, self.city])
address = ' '.join([self.housenumber, middle, address])
# 453 Booth street, Ottawa ON, Canada
elif self.street:
middle = ', '.join([self.street, self.city])
address = ' '.join([middle, address])
# Ottawa ON, Canada
elif self.city:
address = ' '.join([self.city, address])
return address
@property
def country(self):
return self._properties.get('country', '')
@property
def state(self):
if self.osm_value == 'state':
return self._properties.get('name', '')
return self._properties.get('state', '')
@property
def city(self):
if self.osm_value == 'city':
return self._properties.get('name', '')
return self._properties.get('city', '')
@property
def street(self):
return self._properties.get('street', '')
@property
def housenumber(self):
return self._properties.get('housenumber', '')
@property
def postal(self):
return self._properties.get('postcode', '')
@property
def osm_id(self):
return self._properties.get('osm_id', '')
@property
def osm_value(self):
return self._properties.get('osm_value', '')
@property
def osm_key(self):
return self._properties.get('osm_key', '')
@property
def osm_type(self):
return self._properties.get('osm_type', '')
class KomootQuery(MultipleResultsQuery):
"""
Komoot REST API
=======================
API Reference
-------------
http://photon.komoot.de
"""
provider = 'komoot'
method = 'geocode'
_URL = 'http://photon.komoot.de/api'
_RESULT_CLASS = KomootResult
_KEY_MANDATORY = False
def _build_params(self, location, provider_key, **kwargs):
return {
'q': location,
'limit': kwargs.get('maxRows', 1),
'lang': 'en',
}
def _adapt_results(self, json_response):
return json_response['features']
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = KomootQuery('Ottawa Ontario', maxRows=3)
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,45 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.location import Location
from geocoder.komoot import KomootResult, KomootQuery
class KomootReverseResult(KomootResult):
@property
def ok(self):
return bool(self.address)
class KomootReverse(KomootQuery):
"""
Komoot REST API
=======================
API Reference
-------------
http://photon.komoot.de
"""
provider = 'komoot'
method = 'reverse'
_URL = 'https://photon.komoot.de/reverse'
_RESULT_CLASS = KomootReverseResult
def _build_params(self, location, provider_key, **kwargs):
location = Location(location)
return {
'lat': location.lat,
'lon': location.lng,
}
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = KomootReverse("45.4 -75.7")
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

225
geocoder/location.py Normal file
View File

@ -0,0 +1,225 @@
#!/usr/bin/python
# coding: utf8
import re
import geocoder
from six import string_types
try:
from statistics import mean
except ImportError:
def mean(args):
return sum(args) / len(args)
class Location(object):
""" Location container """
lat = None
lng = None
def __init__(self, location, **kwargs):
self.location = location
self.kwargs = kwargs
self._check_input(location)
@property
def ok(self):
return bool(self.latlng)
@staticmethod
def _convert_float(number):
try:
return float(number)
except ValueError:
return None
def _check_input(self, location):
# Checking for a LatLng String
if isinstance(location, string_types):
expression = r"[-]?\d+[.]?[-]?[\d]+"
pattern = re.compile(expression)
match = pattern.findall(location)
if len(match) == 2:
lat, lng = match
self._check_for_list([lat, lng])
else:
# Check for string to Geocode using a provider
provider = self.kwargs.get('provider', 'osm')
g = geocoder.get(location, provider=provider)
if g.ok:
self.lat, self.lng = g.lat, g.lng
# Checking for List of Tuple
elif isinstance(location, (list, tuple)):
self._check_for_list(location)
# Checking for Dictionary
elif isinstance(location, dict):
self._check_for_dict(location)
# Checking for a Geocoder Class
elif hasattr(location, 'latlng'):
if location.latlng:
self.lat, self.lng = location.latlng
# Result into Error
else:
raise ValueError("Unknown location: %s" % location)
def _check_for_list(self, location):
# Standard LatLng list or tuple with 2 number values
if len(location) == 2:
lat = self._convert_float(location[0])
lng = self._convert_float(location[1])
condition_1 = isinstance(lat, float)
condition_2 = isinstance(lng, float)
# Check if input are Floats
if condition_1 and condition_2:
condition_3 = -90 <= lat <= 90
condition_4 = -180 <= lng <= 180
# Check if inputs are within the World Geographical
# boundary (90,180,-90,-180)
if condition_3 and condition_4:
self.lat = lat
self.lng = lng
return self.lat, self.lng
else:
raise ValueError(
"Coords are not within the world's geographical boundary")
else:
raise ValueError("Coordinates must be numbers")
def _check_for_dict(self, location):
# Standard LatLng list or tuple with 2 number values
if 'lat' in location and 'lng' in location:
lat = location['lat']
lng = location['lng']
self._check_for_list([lat, lng])
if 'y' in location and 'x' in location:
lat = location['y']
lng = location['x']
self._check_for_list([lat, lng])
@property
def latlng(self):
if isinstance(self.lat, float) and isinstance(self.lng, float):
return [self.lat, self.lng]
return []
@property
def latitude(self):
return self.lat
@property
def longitude(self):
return self.lng
@property
def xy(self):
if isinstance(self.lat, float) and isinstance(self.lng, float):
return [self.lng, self.lat]
return []
def __str__(self):
if self.ok:
return u'{0}, {1}'.format(self.lat, self.lng)
return u''
class BBox(object):
"""BBox container"""
DEGREES_TOLERANCE = 0.5
@classmethod
def factory(cls, arg):
# validate input first
if not isinstance(arg, (list, dict)):
raise ValueError(
"BBox factory only accept a dict or a list as argument")
# we have a dict... just check which fields are given
if isinstance(arg, dict):
if 'southwest' in arg:
return cls(bounds=arg)
elif 'bbox' in arg:
return cls(bbox=arg['bbox'])
elif 'bounds' in arg:
return cls(bounds=arg['bounds'])
elif 'lat' in arg:
return cls(lat=arg['lat'], lng=arg['lng'])
elif 'west' in arg:
return cls(west=arg['west'], south=arg['south'],
east=arg['east'], north=arg['north'])
else:
raise ValueError(
"Could not found valid values in dict to create a bbox")
# we have a list... guess what to call according to the number of parameters given:
if len(arg) == 2:
lat, lng = arg
return cls(lat=lat, lng=lng)
elif len(arg) == 4:
return cls(bbox=arg)
else:
raise ValueError(
"Could not found valid values in list to create a bbox")
def __init__(self, bbox=None, bounds=None,
lat=None, lng=None,
west=None, south=None, east=None, north=None):
if bounds is not None and bounds.get('southwest') and bounds.get('northeast'):
self.south, self.west = map(float, bounds['southwest'])
self.north, self.east = map(float, bounds['northeast'])
elif bbox is not None and all(bbox):
self.west, self.south, self.east, self.north = map(float, bbox)
elif lat is not None and lng is not None:
self.south = float(lat) - self.DEGREES_TOLERANCE
self.north = float(lat) + self.DEGREES_TOLERANCE
self.west = float(lng) - self.DEGREES_TOLERANCE
self.east = float(lng) + self.DEGREES_TOLERANCE
elif all([west, south, east, north]):
self.west, self.south, self.east, self.north = map(
float, [west, south, east, north])
else:
raise ValueError("Could not create BBox/Bounds from given arguments")
@property
def lat(self):
return mean([self.south, self.north])
@property
def lng(self):
return mean([self.west, self.east])
@property
def latlng(self):
if isinstance(self.lat, float) and isinstance(self.lng, float):
return [self.lat, self.lng]
return []
@property
def latitude(self):
return self.lat
@property
def longitude(self):
return self.lng
@property
def xy(self):
if isinstance(self.lat, float) and isinstance(self.lng, float):
return [self.lng, self.lat]
return []
@property
def as_dict(self):
return {
'northeast': [self.north, self.east],
'southwest': [self.south, self.west]
}
if __name__ == '__main__':
l = Location([0.0, 0.0])
print(l.lng)

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

42
geocoder/locationiq.py Normal file
View File

@ -0,0 +1,42 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
import json
from geocoder.osm import OsmResult, OsmQuery
from geocoder.keys import locationiq_key
class LocationIQResult(OsmResult):
pass
class LocationIQQuery(OsmQuery):
provider = 'locationiq'
method = 'geocode'
_URL = 'https://locationiq.org/v1/search.php'
_RESULT_CLASS = LocationIQResult
_KEY = locationiq_key
_KEY_MANDATORY = True
def _build_params(self, location, provider_key, **kwargs):
if 'limit' in kwargs:
kwargs['maxRows'] = kwargs['limit']
return {
'key': provider_key,
'q': location,
'format': 'json',
'addressdetails': 1,
'limit': kwargs.get('maxRows', 1),
}
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = LocationIQQuery('Ottawa, Ontario')
g.debug()
g = LocationIQQuery('Ottawa, Ontario', maxRows=5)
print(json.dumps(g.geojson, indent=4))

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,14 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.locationiq import LocationIQQuery
class LocationIQReverse(LocationIQQuery):
provider = 'locationiq'
method = 'reverse'
if __name__ == '__main__':
g = LocationIQReverse("45.3, -75.4")
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

151
geocoder/mapbox.py Normal file
View File

@ -0,0 +1,151 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import mapbox_access_token
from geocoder.location import BBox, Location
class MapboxResult(OneResult):
def __init__(self, json_content):
self._geometry = json_content.get('geometry', {})
for item in json_content.get('context', []):
if '.' in item['id']:
# attribute=country & text=Canada
attribute = item['id'].split('.')[0]
json_content[attribute] = item['text']
super(MapboxResult, self).__init__(json_content)
@property
def lat(self):
coord = self._geometry['coordinates']
if coord:
return coord[1]
@property
def lng(self):
coord = self._geometry['coordinates']
if coord:
return coord[0]
@property
def address(self):
return self.raw.get('place_name')
@property
def housenumber(self):
return self.raw.get('address')
@property
def street(self):
return ''
@property
def city(self):
return self.raw.get('place')
@property
def state(self):
return self.raw.get('region')
@property
def country(self):
return self.raw.get('country')
@property
def postal(self):
return self.raw.get('postcode')
@property
def accuracy(self):
if self.interpolated:
return "interpolated"
@property
def quality(self):
return self.raw.get('relevance')
@property
def interpolated(self):
return self._geometry.get('interpolated')
@property
def bbox(self):
_bbox = self.raw.get('bbox')
if _bbox:
west = _bbox[0]
south = _bbox[1]
east = _bbox[2]
north = _bbox[3]
return self._get_bbox(south, west, north, east)
class MapboxQuery(MultipleResultsQuery):
"""
Mapbox Geocoding
================
The Mapbox Geocoding API lets you convert location text into
geographic coordinates (1600 Pennsylvania Ave NW -77.0366,38.8971).
API Reference
-------------
https://www.mapbox.com/developers/api/geocoding/
Get Mapbox Access Token
-----------------------
https://www.mapbox.com/account
"""
provider = 'mapbox'
method = 'geocode'
_URL = u'https://api.mapbox.com/geocoding/v5/mapbox.places/{0}.json'
_RESULT_CLASS = MapboxResult
_KEY = mapbox_access_token
def _build_params(self, location, provider_key, **kwargs):
base_params = {
'access_token': provider_key,
'country': kwargs.get('country'),
'types': kwargs.get('types'),
}
# handle proximity
proximity = kwargs.get('proximity', None)
if proximity is not None:
proximity = Location(proximity)
# do not forget to convert bbox to mapbox expectations...
base_params['proximity'] = u'{longitude},{latitude}'.format(
longitude=proximity.longitude,
latitude=proximity.latitude
)
bbox = kwargs.get('bbox')
if bbox:
bbox = BBox(bbox=bbox)
# do not forget to convert bbox to mapbox expectations...
base_params['bbox'] = u'{west},{south},{east},{north}'.format(
west=bbox.west,
east=bbox.east,
south=bbox.south,
north=bbox.north
)
return base_params
def _before_initialize(self, location, **kwargs):
self.url = self.url.format(location)
def _adapt_results(self, json_response):
# extract the array of JSON objects
return json_response.get('features', [])
if __name__ == '__main__':
g = MapboxQuery("200 Queen Street", proximity=[45.3, -66.1])
print(g.address)
g = MapboxQuery("200 Queen Street")
print(g.address)
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,52 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.mapbox import MapboxResult, MapboxQuery
from geocoder.location import Location
class MapboxReverseResult(MapboxResult):
@property
def ok(self):
return bool(self.address)
class MapboxReverse(MapboxQuery):
"""
Mapbox Reverse Geocoding
========================
Reverse geocoding lets you reverse this process, turning a
pair of lat/lon coordinates into a meaningful place name
(-77.036,38.897 1600 Pennsylvania Ave NW).
API Reference
-------------
https://www.mapbox.com/developers/api/geocoding/
Get Mapbox Access Token
-----------------------
https://www.mapbox.com/account
"""
provider = 'mapbox'
method = 'reverse'
_URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/{lng},{lat}.json'
def _build_params(self, location, provider_key, **kwargs):
return {
'access_token': provider_key,
'country': kwargs.get('country'),
'types': kwargs.get('types'),
}
def _before_initialize(self, location, **kwargs):
self.location = str(Location(location))
lat, lng = Location(location).latlng
self.url = self.url.format(lng=lng, lat=lat)
if __name__ == '__main__':
g = MapboxReverse([45.4049053, -75.7077965])
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

125
geocoder/mapquest.py Normal file
View File

@ -0,0 +1,125 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import mapquest_key
from geocoder.location import BBox
class MapquestResult(OneResult):
@property
def lat(self):
return self.raw.get('latLng', {}).get('lat')
@property
def lng(self):
return self.raw.get('latLng', {}).get('lng')
@property
def street(self):
return self.raw.get('street')
@property
def address(self):
if self.street:
return self.street
elif self.city:
return self.city
elif self.country:
return self.country
@property
def quality(self):
return self.raw.get('geocodeQuality')
@property
def postal(self):
return self.raw.get('postalCode')
@property
def neighborhood(self):
return self.raw.get('adminArea6')
@property
def city(self):
return self.raw.get('adminArea5')
@property
def county(self):
return self.raw.get('adminArea4')
@property
def state(self):
return self.raw.get('adminArea3')
@property
def country(self):
return self.raw.get('adminArea1')
class MapquestQuery(MultipleResultsQuery):
"""
MapQuest
========
The geocoding service enables you to take an address and get the
associated latitude and longitude. You can also use any latitude
and longitude pair and get the associated address. Three types of
geocoding are offered: address, reverse, and batch.
API Reference
-------------
http://www.mapquestapi.com/geocoding/
"""
provider = 'mapquest'
method = 'geocode'
_URL = 'http://www.mapquestapi.com/geocoding/v1/address'
_RESULT_CLASS = MapquestResult
_KEY = mapquest_key
def _build_headers(self, provider_key, **kwargs):
return {
'referer': 'http://www.mapquestapi.com/geocoding/',
'host': 'www.mapquestapi.com',
}
def _build_params(self, location, provider_key, **kwargs):
params = {
'key': provider_key,
'location': location,
'maxResults': kwargs.get("maxRows", 1),
'outFormat': 'json',
}
bbox = kwargs.get('bbox')
if bbox:
bbox = BBox(bbox=bbox)
params['boundingBox'] = u'{north},{west},{south},{east}'.format(
west=bbox.west,
east=bbox.east,
south=bbox.south,
north=bbox.north
)
return params
def _catch_errors(self, json_response):
if b'The AppKey submitted with this request is invalid' in json_response:
self.error = 'MapQuest API Key invalid'
return self.error
def _adapt_results(self, json_response):
results = json_response.get('results', [])
if results:
return results[0]['locations']
return []
if __name__ == '__main__':
g = MapquestQuery('Ottawa', maxRows=3)
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,59 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.base import MultipleResultsQuery
from geocoder.mapquest import MapquestResult
from geocoder.keys import mapquest_key
class MapQuestBatchResult(MapquestResult):
@property
def ok(self):
return bool(self.quality)
class MapquestBatch(MultipleResultsQuery):
"""
MapQuest
========
The geocoding service enables you to take an address and get the
associated latitude and longitude. You can also use any latitude
and longitude pair and get the associated address. Three types of
geocoding are offered: address, reverse, and batch.
API Reference
-------------
http://www.mapquestapi.com/geocoding/
"""
provider = 'mapquest'
method = 'batch'
_RESULT_CLASS = MapQuestBatchResult
_URL = 'http://www.mapquestapi.com/geocoding/v1/batch'
_TIMEOUT = 30
_KEY = mapquest_key
def _build_params(self, location, provider_key, **kwargs):
self._TIMEOUT = kwargs.get('timeout', 30)
return {
'key': provider_key,
'location': location,
'maxResults': 1,
'outFormat': 'json',
}
def _adapt_results(self, json_response):
results = json_response.get('results', [])
if results:
return [result['locations'][0] for result in results]
return []
if __name__ == '__main__':
g = MapquestBatch(['Denver,CO', 'Boulder,CO'])
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,46 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
from geocoder.mapquest import MapquestResult, MapquestQuery
from geocoder.location import Location
class MapQuestReverseResult(MapquestResult):
@property
def ok(self):
return bool(self.quality)
class MapquestReverse(MapquestQuery):
"""
MapQuest
========
The geocoding service enables you to take an address and get the
associated latitude and longitude. You can also use any latitude
and longitude pair and get the associated address. Three types of
geocoding are offered: address, reverse, and batch.
API Reference
-------------
http://www.mapquestapi.com/geocoding/
"""
provider = 'mapquest'
method = 'reverse'
_URL = 'http://www.mapquestapi.com/geocoding/v1/reverse'
def _build_params(self, location, provider_key, **kwargs):
return {
'key': provider_key,
'location': str(Location(location)),
'maxResults': 1,
'outFormat': 'json',
}
if __name__ == '__main__':
g = MapquestReverse([45.50, -76.05])
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

109
geocoder/mapzen.py Normal file
View File

@ -0,0 +1,109 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.location import BBox
from geocoder.base import OneResult, MultipleResultsQuery
from geocoder.keys import mapzen_key
class MapzenResult(OneResult):
def __init__(self, json_content):
# create safe shortcuts
self._geometry = json_content.get('geometry', {})
self._properties = json_content.get('properties', {})
# proceed with super.__init__
super(MapzenResult, self).__init__(json_content)
@property
def lat(self):
return self._geometry['coordinates'][1]
@property
def lng(self):
return self._geometry['coordinates'][0]
@property
def bbox(self):
return BBox.factory(self.latlng).as_dict
@property
def address(self):
return self._properties.get('label')
@property
def housenumber(self):
return self._properties.get('housenumber')
@property
def street(self):
return self._properties.get('street')
@property
def neighbourhood(self):
return self._properties.get('neighbourhood')
@property
def city(self):
return self._properties.get('locality')
@property
def state(self):
return self._properties.get('region')
@property
def country(self):
return self._properties.get('country')
@property
def postal(self):
return self._properties.get('postalcode')
@property
def gid(self):
return self._properties.get('gid')
@property
def id(self):
return self._properties.get('id')
class MapzenQuery(MultipleResultsQuery):
"""
Mapzen REST API
=======================
API Reference
-------------
https://mapzen.com/documentation/search/search/
"""
provider = 'mapzen'
method = 'geocode'
_URL = 'https://search.mapzen.com/v1/search'
_RESULT_CLASS = MapzenResult
_KEY = mapzen_key
def __init__(self, *args, **kwargs):
raise DeprecationWarning('MapZen shut down as of January 2018: https://mapzen.com/blog/shutdown')
def _build_params(self, location, provider_key, **kwargs):
return {
'text': location,
'api_key': provider_key,
'size': kwargs.get('maxRows', 1)
}
def _adapt_results(self, json_response):
return json_response['features']
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = MapzenQuery('201 Spear Street, San Francisco')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

View File

@ -0,0 +1,50 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.mapzen import MapzenResult, MapzenQuery
from geocoder.location import Location
class MapzenReverseResult(MapzenResult):
@property
def ok(self):
return bool(self.address)
class MapzenReverse(MapzenQuery):
"""
Mapzen REST API
=======================
API Reference
-------------
https://mapzen.com/documentation/search/reverse/
"""
provider = 'mapzen'
method = 'reverse'
_URL = 'https://search.mapzen.com/v1/reverse'
_RESULT_CLASS = MapzenReverseResult
def _build_params(self, location, provider_key, **kwargs):
location = Location(location)
return {
'point.lat': location.lat,
'point.lon': location.lng,
'size': kwargs.get('size', 1),
'layers': kwargs.get('layers'),
'source': kwargs.get('sources'),
'boundary.country': kwargs.get('country'),
'api_key': provider_key
}
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = MapzenReverse("45.4049053 -75.7077965", key='search-un1M9Hk')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

140
geocoder/maxmind.py Normal file
View File

@ -0,0 +1,140 @@
#!/usr/bin/python
# coding: utf8
from __future__ import absolute_import
import logging
from geocoder.base import OneResult, MultipleResultsQuery
class MaxmindResults(OneResult):
def __init__(self, json_content):
# create safe shortcuts
self._location = json_content.get('location', {})
self._traits = json_content.get('traits', {})
# proceed with super.__init__
super(MaxmindResults, self).__init__(json_content)
@property
def lat(self):
return self._location.get('latitude')
@property
def lng(self):
return self._location.get('longitude')
@property
def timezone(self):
return self._location.get('time_zone')
@property
def metro_code(self):
return self._location.get('metro_code')
@property
def domain(self):
return self._traits.get('domain')
@property
def isp(self):
return self._traits.get('isp')
@property
def organization(self):
return self._traits.get('organization')
@property
def ip(self):
return self._traits.get('ip_address')
@property
def postal(self):
return self.raw.get('postal', {}).get('code')
@property
def city(self):
return self.raw.get('city', {}).get('names', {}).get('en')
@property
def state(self):
return self.raw.get('subdivision', {}).get('names', {}).get('en')
@property
def country(self):
return self.raw.get('country', {}).get('names', {}).get('en')
@property
def country_code(self):
return self.raw.get('country', {}).get('iso_code')
@property
def continent(self):
return self.raw.get('continent', {}).get('names', {}).get('en')
@property
def continent_code(self):
return self.raw.get('continent', {}).get('code')
@property
def address(self):
if self.city:
return u'{0}, {1}, {2}'.format(self.city, self.state, self.country)
elif self.state:
return u'{0}, {1}'.format(self.state, self.country)
elif self.country:
return u'{0}'.format(self.country)
else:
return u''
class MaxmindQuery(MultipleResultsQuery):
"""
MaxMind's GeoIP2
=======================
MaxMind's GeoIP2 products enable you to identify the location,
organization, connection speed, and user type of your Internet
visitors. The GeoIP2 databases are among the most popular and
accurate IP geolocation databases available.
API Reference
-------------
https://www.maxmind.com/en/geolocation_landing
"""
provider = 'maxmind'
method = 'geocode'
_URL = 'https://www.maxmind.com/geoip/v2.0/city_isp_org/{0}'
_RESULT_CLASS = MaxmindResults
_KEY_MANDATORY = False
def _build_headers(self, provider_key, **kwargs):
return {
'Referer': 'https://www.maxmind.com/en/geoip_demo',
'Host': 'www.maxmind.com',
}
def _build_params(self, location, provider_key, **kwargs):
return {'demo': 1}
def _before_initialize(self, location, **kwargs):
location = location or 'me'
self.url = self._URL.format(location)
def _catch_errors(self, json_response):
error = json_response.get('error')
if error:
self.error = json_response.get('code')
return self.error
def _adapt_results(self, json_response):
return [json_response]
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
g = MaxmindQuery('8.8.8.8')
g.debug()

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=C:\Users\stacy\Downloads\geocoder-1.38.1.tar.gz

Some files were not shown because too many files have changed in this diff Show More