usse/funda-scraper/venv/lib/python3.10/site-packages/geopy/geocoders/mapbox.py

212 lines
7.4 KiB
Python
Raw Normal View History

2023-02-20 22:38:24 +00:00
from functools import partial
from urllib.parse import quote, urlencode
from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
from geopy.location import Location
from geopy.point import Point
from geopy.util import logger
__all__ = ("MapBox", )
class MapBox(Geocoder):
"""Geocoder using the Mapbox API.
Documentation at:
https://www.mapbox.com/api-documentation/
"""
api_path = '/geocoding/v5/mapbox.places/%(query)s.json/'
def __init__(
self,
api_key,
*,
scheme=None,
timeout=DEFAULT_SENTINEL,
proxies=DEFAULT_SENTINEL,
user_agent=None,
ssl_context=DEFAULT_SENTINEL,
adapter_factory=None,
domain='api.mapbox.com',
referer=None
):
"""
:param str api_key: The API key required by Mapbox to perform
geocoding requests. API keys are managed through Mapox's account
page (https://www.mapbox.com/account/access-tokens).
:param str scheme:
See :attr:`geopy.geocoders.options.default_scheme`.
:param int timeout:
See :attr:`geopy.geocoders.options.default_timeout`.
:param dict proxies:
See :attr:`geopy.geocoders.options.default_proxies`.
:param str user_agent:
See :attr:`geopy.geocoders.options.default_user_agent`.
:type ssl_context: :class:`ssl.SSLContext`
:param ssl_context:
See :attr:`geopy.geocoders.options.default_ssl_context`.
:param callable adapter_factory:
See :attr:`geopy.geocoders.options.default_adapter_factory`.
.. versionadded:: 2.0
:param str domain: base api domain for mapbox
:param str referer: The URL used to satisfy the URL restriction of
mapbox tokens.
.. versionadded:: 2.3
"""
super().__init__(
scheme=scheme,
timeout=timeout,
proxies=proxies,
user_agent=user_agent,
ssl_context=ssl_context,
adapter_factory=adapter_factory,
)
self.api_key = api_key
self.domain = domain.strip('/')
self.api = "%s://%s%s" % (self.scheme, self.domain, self.api_path)
if referer:
self.headers['Referer'] = referer
def _parse_json(self, json, exactly_one=True):
'''Returns location, (latitude, longitude) from json feed.'''
features = json['features']
if features == []:
return None
def parse_feature(feature):
location = feature['place_name']
longitude = feature['geometry']['coordinates'][0]
latitude = feature['geometry']['coordinates'][1]
return Location(location, (latitude, longitude), feature)
if exactly_one:
return parse_feature(features[0])
else:
return [parse_feature(feature) for feature in features]
def geocode(
self,
query,
*,
exactly_one=True,
timeout=DEFAULT_SENTINEL,
proximity=None,
country=None,
language=None,
bbox=None
):
"""
Return a location point by address.
:param str query: The address or query you wish to geocode.
:param bool exactly_one: Return one result or a list of results, if
available.
:param int timeout: Time, in seconds, to wait for the geocoding service
to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
exception. Set this only if you wish to override, on this call
only, the value set during the geocoder's initialization.
:param proximity: A coordinate to bias local results based on a provided
location.
:type proximity: :class:`geopy.point.Point`, list or tuple of ``(latitude,
longitude)``, or string as ``"%(latitude)s, %(longitude)s"``.
:param country: Country to filter result in form of
ISO 3166-1 alpha-2 country code (e.g. ``FR``).
Might be a Python list of strings.
:type country: str or list
:param str language: This parameter controls the language of the text supplied in
responses, and also affects result scoring, with results matching the users
query in the requested language being preferred over results that match in
another language. You can pass two letters country codes (ISO 639-1).
.. versionadded:: 2.3
:param bbox: The bounding box of the viewport within which
to bias geocode results more prominently.
Example: ``[Point(22, 180), Point(-22, -180)]``.
:type bbox: list or tuple of 2 items of :class:`geopy.point.Point` or
``(latitude, longitude)`` or ``"%(latitude)s, %(longitude)s"``.
:rtype: ``None``, :class:`geopy.location.Location` or a list of them, if
``exactly_one=False``.
"""
params = {}
params['access_token'] = self.api_key
if bbox:
params['bbox'] = self._format_bounding_box(
bbox, "%(lon1)s,%(lat1)s,%(lon2)s,%(lat2)s")
if not country:
country = []
if isinstance(country, str):
country = [country]
if country:
params['country'] = ",".join(country)
if proximity:
p = Point(proximity)
params['proximity'] = "%s,%s" % (p.longitude, p.latitude)
if language:
params['language'] = language
quoted_query = quote(query.encode('utf-8'))
url = "?".join((self.api % dict(query=quoted_query),
urlencode(params)))
logger.debug("%s.geocode: %s", self.__class__.__name__, url)
callback = partial(self._parse_json, exactly_one=exactly_one)
return self._call_geocoder(url, callback, timeout=timeout)
def reverse(
self,
query,
*,
exactly_one=True,
timeout=DEFAULT_SENTINEL
):
"""
Return an address by location point.
:param query: The coordinates for which you wish to obtain the
closest human-readable addresses.
:type query: :class:`geopy.point.Point`, list or tuple of ``(latitude,
longitude)``, or string as ``"%(latitude)s, %(longitude)s"``.
:param bool exactly_one: Return one result or a list of results, if
available.
:param int timeout: Time, in seconds, to wait for the geocoding service
to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
exception. Set this only if you wish to override, on this call
only, the value set during the geocoder's initialization.
:rtype: ``None``, :class:`geopy.location.Location` or a list of them, if
``exactly_one=False``.
"""
params = {}
params['access_token'] = self.api_key
point = self._coerce_point_to_string(query, "%(lon)s,%(lat)s")
quoted_query = quote(point.encode('utf-8'))
url = "?".join((self.api % dict(query=quoted_query),
urlencode(params)))
logger.debug("%s.reverse: %s", self.__class__.__name__, url)
callback = partial(self._parse_json, exactly_one=exactly_one)
return self._call_geocoder(url, callback, timeout=timeout)