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') |