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 @ 564

History | View | Annotate | Download (6.46 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
            user_agent=None
32
        ):
33
        """
34
        Initialize a customized Baidu geocoder using the v2 API.
35

36
        .. versionadded:: 1.0.0
37

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

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

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

    
58

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

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

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

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

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

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

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

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

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

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

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

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

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

    
130

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

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

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

    
144

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

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

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

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

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

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