高德地图POI爬虫避坑指南:从API申请到数据清洗的完整流程
高德地图POI数据采集实战从API申请到数据落地的避坑手册第一次用高德地图API采集商圈数据时我对着报错的JSON响应愣了两小时——明明文档里的示例代码可以直接运行为什么我的请求总是返回INVALID_USER_KEY这种经历恐怕每个爬虫开发者都不陌生。本文将分享一套经过实战检验的POI采集方案覆盖密钥管理、异常处理、数据清洗等关键环节特别适合那些已经掌握Python基础但需要提升工程化能力的开发者。1. 高德API申请与密钥安全策略很多教程对API申请环节一笔带过但这恰恰是第一个坑。高德开发者平台提供三种密钥类型其中Web服务API才是我们需要的。注册时注意选择个人开发者而非企业认证否则需要额外提交营业执照等材料。密钥安全的最佳实践永远不要将API密钥硬编码在代码中包括Jupyter Notebook不同环境开发/生产使用不同密钥设置IP白名单限制调用来源通过环境变量管理密钥# 在~/.bashrc中添加 export AMAP_KEY你的实际密钥调用时通过os模块读取import os api_key os.environ.get(AMAP_KEY)免费版每日限额2000次调用超过后会被临时封禁。建议在代码中加入用量监控def check_quota(response): quota response.headers.get(X-RateLimit-Remaining) if quota and int(quota) 100: print(f警告剩余调用次数仅剩{quota})2. 健壮性请求设计与异常处理直接使用requests.get()而不做超时设置是新手常见错误。高德API有时响应较慢需要合理配置超时参数params { key: api_key, keywords: 咖啡厅, city: 上海, offset: 20, page: 1, output: json } try: response requests.get( https://restapi.amap.com/v3/place/text, paramsparams, timeout(3.05, 27) # 连接超时3秒读取超时27秒 ) response.raise_for_status() except requests.exceptions.Timeout: print(请求超时建议重试) except requests.exceptions.RequestException as e: print(f网络请求异常: {str(e)})对于API返回的错误码需要特别处理错误码含义建议处理方式INVALID_USER_KEY密钥无效检查密钥是否过期或被重置DAILY_QUERY_OVER_LIMIT超过日限额切换备用密钥或等待次日IP_FORBIDDENIP被禁止检查是否配置了IP白名单SERVICE_NOT_EXIST服务不存在检查API端点URL是否正确3. 复杂JSON解析与数据清洗技巧高德返回的POI数据结构嵌套较深建议先打印原始响应查看结构。常见问题包括字段缺失处理def safe_get(poi, field, default): 安全获取可能缺失的字段 value poi.get(field) return default if value in [None, , []] else value # 使用示例 phone safe_get(poi, tel, 暂无)经纬度分割location字段是经度,纬度字符串需要拆分为独立字段def split_location(loc_str): try: lng, lat map(float, loc_str.split(,)) return {lng: lng, lat: lat} except: return {lng: None, lat: None}行政区划信息提取pname省、cityname市、adname区可能不一致建议建立校验机制def validate_region(pname, cityname, adname): if not all([pname, cityname, adname]): return False # 可添加具体校验逻辑 return True4. 存储方案设计与性能优化小规模数据可以使用CSV但建议直接使用SQLiteimport sqlite3 def init_db(db_pathpoi.db): conn sqlite3.connect(db_path) cursor conn.cursor() cursor.execute( CREATE TABLE IF NOT EXISTS poi ( id TEXT PRIMARY KEY, name TEXT, category TEXT, lng REAL, lat REAL, province TEXT, city TEXT, district TEXT, address TEXT, phone TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP ) ) conn.commit() return conn批量插入优化def batch_insert(conn, pois): sql INSERT OR IGNORE INTO poi (id, name, category, lng, lat, province, city, district, address, phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) data [ (poi[id], poi[name], poi[type], split_location(poi[location])[lng], split_location(poi[location])[lat], poi[pname], poi[cityname], poi[adname], poi[address], safe_get(poi, tel)) for poi in pois ] conn.executemany(sql, data) conn.commit()5. 反爬策略与合规采集虽然高德没有严格的反爬机制但仍需注意控制请求频率建议每秒不超过5次添加随机延迟import random import time def random_delay(): time.sleep(random.uniform(0.1, 0.5))使用User-Agent轮换user_agents [ Mozilla/5.0 (Windows NT 10.0; Win64; x64)..., Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)... ] headers {User-Agent: random.choice(user_agents)}记得在代码中加入注释说明数据用途这既是良好习惯也能在需要向高德说明采集目的时提供依据。