Python Google Geocoding API - IndexError:列表索引超出范围?

Posted

技术标签:

【中文标题】Python Google Geocoding API - IndexError:列表索引超出范围?【英文标题】:Python Google Geocoding API - IndexError: list index out of range? 【发布时间】:2015-05-22 14:47:57 【问题描述】:

我正在从事一个可视化位置数据的个人项目,在这里我通过Geocoding API 对来自 Google 的位置数据进行反向地理编码,方法是为其提供坐标并检索城市名称和国家/地区。

这是一个 CSV 文件,有 2 列:“位置”(纬度和经度)和“时间”(日期+时间)。共有 8533 行。

样本数据:

    Location                Time
--------------------------------------------------
| 41.2911084,2.0779035 | 4/15/2015 10:58         |
--------------------------------------------------
| 41.2885014,2.0725591 | 4/15/2015 10:07         |
--------------------------------------------------
| 41.3484125,2.1442487 | 4/15/2015 9:56          |
--------------------------------------------------

API 有问题,我一直收到错误消息。让我先展示一下代码。

# import necessary modules
import pandas as pd
import json, requests, logging

# configure logging for our tool
lfh = logging.FileHandler('reverseGeocoder.log')
lfh.setFormatter(logging.Formatter('%(levelname)s %(asctime)s %(message)s'))
log = logging.getLogger('reverseGeocoder')
log.setLevel(logging.INFO)
log.addHandler(lfh)

# load the gps coordinate data
df = pd.read_csv('LocationHistory.csv')

# create new columns
df['geocode_data'] = ''
df['city'] = ''
df['country'] = ''


df.head()

# function that handles the geocoding requests
def reverseGeocode(latlng):

    result = 
    url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=0&key=1'
    apikey = 'API_KEY_GOES_HERE'

    request = url.format(latlng, apikey)
    log.info(request)
    data = json.loads(requests.get(request).text)
    log.info(data)
    result = data['results'][0]['address_components']
    return 
        'city': result[3]['long_name'],
        'country': result[6]['long_name']
    

# comment out the following line of code to geocode the entire dataframe
#df = df.head()

for i, row in df.iterrows():
    # for each row in the dataframe, geocode the lat-long data
    revGeocode = reverseGeocode(df['Location'][i])
    df['geocode_data'][i] = revGeocode
    df['city'] = revGeocode['city']
    df['country'] = revGeocode['country']


    # once every 100 loops print a counter
    #if i % 100 == 0: 
    print i

df.head()

df.to_csv('LocationHistory2.csv', encoding='utf-8', index=False)

我不断收到的有问题的错误:

Traceback (most recent call last):
  File "D:\...\ReverseGeocoding.py", line 45, in <module>
    revGeocode = reverseGeocode(df['Location'][i])
  File "D:\...\ReverseGeocoding.py", line 37, in reverseGeocode
    'country': result[6]['long_name']
IndexError: list index out of range

我认为问题的一部分是我需要进行检查,以防 API 没有为这些位置返回任何内容。为什么它不会返回任何东西,我不知道。

我对 API(和 Python)的世界还很陌生,但是我怎样才能让这段代码处于运行状态呢?

【问题讨论】:

【参考方案1】:

您可能希望检查所需地址属性的类型键。所以试试类似的东西;

    result = data['results'][0]['address_components']
    city = ''
    country = ''

    for item in result:
        if 'administrative_area_level_1' in item[types]:
            city = item['long_name']
        elif 'country' in item[types]:
            country = item['long_name']
    return 
        'city': city,
        'country': country
    

【讨论】:

这对我有用。刚刚将item[type] 更改为item['type']【参考方案2】:

我认为问题的一部分是我需要检查到位, 以防 API 不返回任何位置信息。

确实如此。您要做的第一件事是将您的 requests 调用放入 try/except 块中,以便在请求阶段捕获 possible exceptions(在执行 HTTP 请求时有很多事情可能会出错)。

顺便说一句,您不必手动构建查询字符串 - requests takes care of it 以更安全的方式(转义等),如果您愿意,您仍然可以访问 response 对象中的结果 url它。所以作为你想要的初学者:

url = 'https://maps.googleapis.com/maps/api/geocode/json'
apikey = 'API_KEY_GOES_HERE'
try:
    response = requests.get(url, params="key":apikey, "latlng":latlng)
except requests.exceptions.RequestException as e:
    # this will log the whole traceback
    logger.exception("call failed with %s", e)
    # here you either re-raise the exception, raise your own exception,
    # or return anything
    return None

现在您还想检查response's status code - 200 以外的任何内容都表示您没有数据

if response.status_code != 200:
    logger.error("got status code %s", response.status_code)
    # idem, either raise your own exception or
    # return anything
    return None

FWIW,response 有一个 raise_for_status() method,如果您收到 4XX 或 5XX 响应,它将引发 RequestException,因此您可以将整个事情简化为:

try:
    response = requests.get(url, params="key":apikey, "latlng":latlng)
    response.raise_for_status()
except requests.exceptions.RequestException as e:
    # this will log the whole traceback
    logger.exception("call failed with %s", e)
    # here you either re-raise the exception, raise your own exception,
    # or return anything
    return None

现在您可以预期您确实有一个有效的响应,所以让我们获取我们的 json 数据。同样,requests 已经提供了一个快捷方式。请注意,如果您的响应的内容类型不是“application/json”或响应的内容是无效的 json,您会得到一个ValueError,但是我认为我们可以信任 google 来完成这项工作;)

data = response.json()

我不记得确切的整个地理编码 API,所以应该仔细检查文档,但 IIRC 只要你有 200,你应该有一些有效的数据。

“为什么它不会返回任何东西,我不知道。”

连接丢失、API 限制、服务器宕机(是的),有很多可能的原因。通过上面的代码,你至少应该得到一个提示。

现在您可能仍然没有在结果数据中拥有您所期望的一切 - 再次在这里检查文档,手动重放失败的 geoloc 请求并检查响应和数据等。

【讨论】:

感谢您的快速回复,当我尝试将 try/except 块放在 apikey 下方的 reverseGeocode() 中时,我不断收到缩进错误。它应该可以工作,但一直说unexpected indent。我做错了什么? 编辑:修复了这个问题,但一直收到我之前的错误。

以上是关于Python Google Geocoding API - IndexError:列表索引超出范围?的主要内容,如果未能解决你的问题,请参考以下文章

php Ejemplo API Rest - Google Maps Geocoding

Google Maps Geocoding API 使用限制

Google Geocoding API 返回错误的地址,但 Google 地图显示正确的位置

python 通过百度/高德Geocoding API 获取经纬度数据

Google Maps Geocoding API,其 JS api 中缺少的 API 功能(?)

Google Geocoding v2 API 突然停止工作