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