2014-01-21 7 views
4

Я использую Google Place API для поиска места:пейджинга на Google Places API возвращает статус invalid_request

https://developers.google.com/places/documentation/search

После первого запроса АФИ, я получаю следующую страницу, установив pagetoken. Если я жду 2 секунды между запросами, он работает, но я замечаю, что если я сделаю следующий запрос сразу после предыдущего, он вернет статус INVALID_REQUEST.

Является ли это своего рода ограничение скорости? Я не вижу этого нигде в документации.

https://developers.google.com/places/usage

Поскольку каждый запрос имеет 20 мест, получить список из 100 результатов займет более 10 секунд, который долгое время для кого-то ждать, используя приложение.

ответ

14

Документально, см documentation

По умолчанию каждый Рядом Поиск или Text Search возвращает до 20 результатов истеблишмента в запроса; однако каждый поиск может возвращать до 60 результатов, разделенных на три страницы. Если в вашем поиске, будет возвращено более 20, тогда ответ поиска будет включать в себя следующее значение - next_page_token. Передайте значение next_page_token в параметр pagetoken новый поиск, чтобы увидеть следующий набор результатов. Если next_page_token имеет значение null или не возвращается , то дальнейших результатов не будет. Существует короткая задержка между тем, когда выдается next_page_token и когда она станет действительной. При запросе следующей страницы перед этим будет возвращен ответ INVALID_REQUEST. Повторная попытка запроса с тем же next_page_token вернет следующую страницу результатов.

+0

Спасибо, я не видел этого. Я смотрел в документах по ограничению скорости. Кроме того, факт, что это 60 макс. –

+0

Извините, у меня задержка на 500 секунд. Что происходит с моим приложением? Это потому, что я запросил API более 10000 раз в час и запросил около 25000 раз? –

+0

Это другой вопрос. – geocodezip

4

Хотя я не уверен на 100%, это причина, я оставлю этот ответ здесь, поскольку мне понадобилось около 6 часов, чтобы понять это и может кому-то помочь.

Как указано geocodezip в его ответе, есть небольшая задержка между возвращаемым токеном следующей страницы и фактической доступностью этой страницы. Поэтому я не нашел другого способа исправить это, кроме как использовать какой-то sleep.

Но то, что я не узнал, что каждый запроса после первого INVALID_REQUEST ответа также дает INVALID_REQUEST ответ, независимо от того, если бы я подождал, 1, 2 или 10 секунд.

Я подозреваю, что это как-то связано с кэшированным ответом от Части Google. Решение, которое я нашел, заключается в том, чтобы добавить к URL-адресу произвольный добавочный новый параметр, чтобы сделать его «другим» URL-адресом, поэтому запрашивая безрисковый ответ.

Параметр, который я использовал, был request_count, и для каждого сделанного запроса я увеличил его на 1.

Для иллюстрации, вот код Python POC Я использовал (не копипаст, как это только POC фрагмент кода и не будет работать):

# If except raises, it's most likely due to an invalid api key 
# The while True is used to keep trying a new key each time 
query_result_next_page = None 
google_places = GooglePlaces(api_key) 
invalid_requests_found = 0 
request_count = 0 
while True: 

    request_count = request_count + 1 

    try: 
     query_result = google_places.nearby_search(
       lat_lng={'lat': event['latitude'], 'lng': event['longitude']}, 
       radius=event['radius'], 
       pagetoken=query_result_next_page, 
       request_count=request_count) 

     # If there are additional result pages, lets get it on the next while step 
     if query_result.has_next_page_token: 
      query_result_next_page = query_result.next_page_token 
     else: 
      break 

    except Exception as e: 
     # If the key is over the query limit, try a new one 
     if str(e).find('OVER_QUERY_LIMIT') != -1: 
      logInfo("Key "+api_key+" unavailable.") 
      self.set_unavailable_apikey(api_key) 
      api_key = self.get_api_key() 
     # Sometimes the Places API doesn't create the next page 
     # despite having a next_page_key and throws an INVALID_REQUEST. 
     # We should just sleep for a bit and try again. 
     elif str(e).find('INVALID_REQUEST') != -1: 
      # Maximum of 4 INVALID_REQUEST responses 
      invalid_requests_found = invalid_requests_found + 1 
      if invalid_requests_found > 4: 
       raise e 

      time.sleep(1) 
      continue 
     # If it is another error, different from zero results, raises an exception 
     elif str(e).find('ZERO_RESULTS') == -1: 
      raise e 
     else: 
      break 

EDIT: Забыл упомянуть, что GooglePlaces объект от slimkrazy's Google API lib. К сожалению, мне пришлось настроить код фактического lib, чтобы принять этот новый параметр request_count.

мне пришлось заменить метод nearby_search этого:

def nearby_search(self, language=lang.ENGLISH, keyword=None, location=None, 
      lat_lng=None, name=None, radius=3200, rankby=ranking.PROMINENCE, 
      sensor=False, type=None, types=[], pagetoken=None, request_count=0): 
    """Perform a nearby search using the Google Places API. 

    One of either location, lat_lng or pagetoken are required, the rest of 
    the keyword arguments are optional. 

    keyword arguments: 
    keyword -- A term to be matched against all available fields, including 
       but not limited to name, type, and address (default None) 
    location -- A human readable location, e.g 'London, England' 
       (default None) 
    language -- The language code, indicating in which language the 
       results should be returned, if possible. (default lang.ENGLISH) 
    lat_lng -- A dict containing the following keys: lat, lng 
       (default None) 
    name  -- A term to be matched against the names of the Places. 
       Results will be restricted to those containing the passed 
       name value. (default None) 
    radius -- The radius (in meters) around the location/lat_lng to 
       restrict the search to. The maximum is 50000 meters. 
       (default 3200) 
    rankby -- Specifies the order in which results are listed : 
       ranking.PROMINENCE (default) or ranking.DISTANCE 
       (imply no radius argument). 
    sensor -- Indicates whether or not the Place request came from a 
       device using a location sensor (default False). 
    type  -- Optional type param used to indicate place category. 
    types -- An optional list of types, restricting the results to 
       Places (default []). If there is only one item the request 
       will be send as type param. 
    pagetoken-- Optional parameter to force the search result to return the next 
       20 results from a previously run search. Setting this parameter 
       will execute a search with the same parameters used previously. 
       (default None) 
    """ 
    if location is None and lat_lng is None and pagetoken is None: 
     raise ValueError('One of location, lat_lng or pagetoken must be passed in.') 
    if rankby == 'distance': 
     # As per API docs rankby == distance: 
     # One or more of keyword, name, or types is required. 
     if keyword is None and types == [] and name is None: 
      raise ValueError('When rankby = googleplaces.ranking.DISTANCE, ' + 
          'name, keyword or types kwargs ' + 
          'must be specified.') 
    self._sensor = sensor 
    radius = (radius if radius <= GooglePlaces.MAXIMUM_SEARCH_RADIUS 
       else GooglePlaces.MAXIMUM_SEARCH_RADIUS) 
    lat_lng_str = self._generate_lat_lng_string(lat_lng, location) 
    self._request_params = {'location': lat_lng_str} 
    if rankby == 'prominence': 
     self._request_params['radius'] = radius 
    else: 
     self._request_params['rankby'] = rankby 
    if type: 
     self._request_params['type'] = type 
    elif types: 
     if len(types) == 1: 
      self._request_params['type'] = types[0] 
     elif len(types) > 1: 
      self._request_params['types'] = '|'.join(types) 
    if keyword is not None: 
     self._request_params['keyword'] = keyword 
    if name is not None: 
     self._request_params['name'] = name 
    if pagetoken is not None: 
     self._request_params['pagetoken'] = pagetoken 
    if language is not None: 
     self._request_params['language'] = language 
    self._request_params['request_count'] = request_count 
    self._add_required_param_keys() 
    url, places_response = _fetch_remote_json(
      GooglePlaces.NEARBY_SEARCH_API_URL, self._request_params) 
    _validate_response(url, places_response) 
    return GooglePlacesSearchResult(self, places_response) 
Смежные вопросы