Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / geopy / geocoders / baidu.py @ 545

History | View | Annotate | Download (6.41 KB)

1
"""
2
:class:`.Baidu` is the Baidu Maps geocoder.
3
"""
4

    
5
from geopy.compat import urlencode
6
from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT
7
from geopy.exc import (
8
    GeocoderQueryError,
9
    GeocoderQuotaExceeded,
10
    GeocoderAuthenticationFailure,
11
)
12
from geopy.location import Location
13
from geopy.util import logger
14

    
15

    
16
__all__ = ("Baidu", )
17

    
18

    
19
class Baidu(Geocoder):
20
    """
21
    Geocoder using the Baidu Maps v2 API. Documentation at:
22
        http://developer.baidu.com/map/webservice-geocoding.htm
23
    """
24

    
25
    def __init__(
26
            self,
27
            api_key,
28
            scheme='http',
29
            timeout=DEFAULT_TIMEOUT,
30
            proxies=None,
31
        ):
32
        """
33
        Initialize a customized Baidu geocoder using the v2 API.
34

35
        .. versionadded:: 1.0.0
36

37
        :param string api_key: The API key required by Baidu Map to perform
38
            geocoding requests. API keys are managed through the Baidu APIs
39
            console (http://lbsyun.baidu.com/apiconsole/key).
40

41
        :param string scheme: Use 'https' or 'http' as the API URL's scheme.
42
            Default is http and only http support.
43

44
        :param dict proxies: If specified, routes this geocoder's requests
45
            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
46
            more information, see documentation on
47
            :class:`urllib2.ProxyHandler`.
48
        """
49
        super(Baidu, self).__init__(
50
            scheme=scheme, timeout=timeout, proxies=proxies
51
        )
52
        self.api_key = api_key
53
        self.scheme = scheme
54
        self.doc = {}
55
        self.api = 'http://api.map.baidu.com/geocoder/v2/'
56

    
57

    
58
    @staticmethod
59
    def _format_components_param(components):
60
        """
61
        Format the components dict to something Baidu understands.
62
        """
63
        return "|".join(
64
            (":".join(item)
65
             for item in components.items()
66
            )
67
        )
68

    
69
    def geocode(
70
            self,
71
            query,
72
            exactly_one=True,
73
            timeout=None
74
        ):
75
        """
76
        Geocode a location query.
77

78
        :param string query: The address or query you wish to geocode.
79

80
        :param bool exactly_one: Return one result or a list of results, if
81
            available.
82

83
        :param int timeout: Time, in seconds, to wait for the geocoding service
84
            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
85
            exception. Set this only if you wish to override, on this call
86
            only, the value set during the geocoder's initialization.
87

88
        """
89
        params = {
90
            'ak': self.api_key,
91
            'output': 'json',
92
            'address': self.format_string % query,
93
        }
94

    
95
        url = "?".join((self.api, urlencode(params)))
96
        logger.debug("%s.geocode: %s", self.__class__.__name__, url)
97
        return self._parse_json(
98
            self._call_geocoder(url, timeout=timeout), exactly_one=exactly_one
99
        )
100

    
101
    def reverse(self, query, timeout=None):  # pylint: disable=W0221
102
        """
103
        Given a point, find an address.
104

105
        :param query: The coordinates for which you wish to obtain the
106
            closest human-readable addresses.
107
        :type query: :class:`geopy.point.Point`, list or tuple of (latitude,
108
            longitude), or string as "%(latitude)s, %(longitude)s"
109

110
        :param int timeout: Time, in seconds, to wait for the geocoding service
111
            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
112
            exception. Set this only if you wish to override, on this call
113
            only, the value set during the geocoder's initialization.
114

115
        """
116
        params = {
117
            'ak': self.api_key,
118
            'output': 'json',
119
            'location': self._coerce_point_to_string(query),
120
        }
121

    
122
        url = "?".join((self.api, urlencode(params)))
123

    
124
        logger.debug("%s.reverse: %s", self.__class__.__name__, url)
125
        return self._parse_reverse_json(
126
            self._call_geocoder(url, timeout=timeout)
127
        )
128

    
129

    
130
    @staticmethod
131
    def _parse_reverse_json(page):
132
        """
133
        Parses a location from a single-result reverse API call.
134
        """
135
        place = page.get('result')
136

    
137
        location = place.get('formatted_address').encode('utf-8')
138
        latitude = place['location']['lat']
139
        longitude = place['location']['lng']
140

    
141
        return Location(location, (latitude, longitude), place)
142

    
143

    
144
    def _parse_json(self, page, exactly_one=True):
145
        """
146
        Returns location, (latitude, longitude) from JSON feed.
147
        """
148

    
149
        place = page.get('result', None)
150

    
151
        if not place:
152
            self._check_status(page.get('status'))
153
            return None
154

    
155
        def parse_place(place):
156
            """
157
            Get the location, lat, lng from a single JSON place.
158
            """
159
            location = place.get('level')
160
            latitude = place['location']['lat']
161
            longitude = place['location']['lng']
162
            return Location(location, (latitude, longitude), place)
163

    
164
        if exactly_one:
165
            return parse_place(place)
166
        else:
167
            return [parse_place(item) for item in place]
168

    
169
    @staticmethod
170
    def _check_status(status):
171
        """
172
        Validates error statuses.
173
        """
174
        if status == '0':
175
            # When there are no results, just return.
176
            return
177
        if status == '1':
178
            raise GeocoderQueryError(
179
                'Internal server error.'
180
            )
181
        elif status == '2':
182
            raise GeocoderQueryError(
183
                'Invalid request.'
184
            )
185
        elif status == '3':
186
            raise GeocoderAuthenticationFailure(
187
                'Authentication failure.'
188
            )
189
        elif status == '4':
190
            raise GeocoderQuotaExceeded(
191
                'Quota validate failure.'
192
            )
193
        elif status == '5':
194
            raise GeocoderQueryError(
195
                'AK Illegal or Not Exist.'
196
            )
197
        elif status == '101':
198
            raise GeocoderQueryError(
199
                'Your request was denied.'
200
            )
201
        elif status == '102':
202
            raise GeocoderQueryError(
203
                'IP/SN/SCODE/REFERER Illegal:'
204
            )
205
        elif status == '2xx':
206
            raise GeocoderQueryError(
207
                'Has No Privilleges.'
208
            )
209
        elif status == '3xx':
210
            raise GeocoderQuotaExceeded(
211
                'Quota Error.'
212
            )
213
        else:
214
            raise GeocoderQueryError('Unknown error')