4. HTTP API数据采集:RESTful API概念、使用requests库调用天气API、解析JSON响应、异常处理
好,咱们进入数据采集的第四个环节——HTTP API。说实话,这是目前环境数据采集中最常用的方式之一。你想想看,现在哪个气象站、哪个监测平台不提供API接口?我做了这么多年环境数据工程,90%以上的实时数据都是通过API拿到的。
4.1 RESTful API,说白了就是一套约定
RESTful API这个概念,刚接触时容易觉得玄乎。其实没那么复杂。它就是一套设计规范,告诉你怎么通过HTTP协议去操作数据。
我个人习惯把RESTful API理解成「数据超市」:
- 资源:就是货架上的商品,比如天气数据、空气质量指数
- URL:就是商品的货架编号,比如
/api/weather - HTTP方法:就是你对商品的操作——GET是看看,POST是放进去,PUT是换一个,DELETE是扔掉
我在项目中遇到过不少新手,一上来就问我「老师,RESTful到底啥意思?」我的回答永远是:你先记住GET和POST就够了,其他后面慢慢来。
4.2 用requests库,三行代码搞定天气API
Python的requests库,是我用过最顺手的HTTP工具。没有之一。它的设计哲学就是「让HTTP变得人性化」。
先看一个最简单的例子——调用天气API:
import requests
# 这是我常用的一个免费天气API
url = "https://api.openweathermap.org/data/2.5/weather"
params = {
"q": "Beijing",
"appid": "你的API密钥",
"units": "metric" # 摄氏度
}
response = requests.get(url, params=params)
print(response.status_code) # 200表示成功
print(response.text) # 原始JSON字符串
嗯,这里要注意:params参数会自动帮你拼接到URL后面。你不需要自己写?q=Beijing&appid=xxx,requests全帮你干了。我刚开始用的时候还傻乎乎自己拼接字符串,后来发现这简直是自找麻烦。
4.3 解析JSON响应,别用手动字符串切割
API返回的数据通常是JSON格式。说白了就是Python里的字典嵌套列表。解析起来非常简单:
import requests
url = "https://api.openweathermap.org/data/2.5/weather"
params = {
"q": "Beijing",
"appid": "你的API密钥",
"units": "metric"
}
response = requests.get(url, params=params)
# 直接解析成Python字典
data = response.json()
# 提取关键字段
temperature = data['main']['temp']
humidity = data['main']['humidity']
description = data['weather'][0]['description']
print(f"北京当前温度:{temperature}°C")
print(f"湿度:{humidity}%")
print(f"天气描述:{description}")
你可能会问:为什么不直接用response.text然后自己用正则或者字符串切割?我曾经也这么干过,结果被坑惨了——JSON结构稍微一变,代码就崩了。用.json()方法,既安全又省心。
data.keys()看看顶层有哪些字段。很多API的文档写得不够清楚,自己探索反而更快。
4.4 异常处理,别让程序裸奔
做数据采集,最怕的就是程序跑着跑着突然崩了。网络超时、API限流、服务器500错误……这些我在项目中都遇到过。所以异常处理不是锦上添花,是保命技能。
来看一个健壮的采集代码:
import requests
import time
def fetch_weather_data(city, api_key, retries=3):
"""
带重试机制的天气数据采集函数
"""
url = "https://api.openweathermap.org/data/2.5/weather"
params = {
"q": city,
"appid": api_key,
"units": "metric"
}
for attempt in range(retries):
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status() # 检查HTTP状态码
data = response.json()
return data
except requests.exceptions.Timeout:
print(f"第{attempt+1}次尝试超时,正在重试...")
time.sleep(2)
except requests.exceptions.HTTPError as e:
if response.status_code == 429:
print("API限流了,等一会儿再试")
time.sleep(5)
elif response.status_code == 404:
print(f"城市{city}不存在,检查一下参数")
return None
else:
print(f"HTTP错误:{e}")
return None
except requests.exceptions.ConnectionError:
print("网络连接失败,检查网络或API地址")
return None
except Exception as e:
print(f"未知错误:{e}")
return None
print("重试次数用尽,采集失败")
return None
# 使用示例
api_key = "你的API密钥"
weather_data = fetch_weather_data("Beijing", api_key)
if weather_data:
print(f"采集成功:{weather_data['main']['temp']}°C")
timeout参数,结果某个API服务器挂了,程序卡在那里整整8小时,数据管道全堵死了。从那以后,我所有HTTP请求必加timeout。
4.5 知识体系一览
下面这张图,是我梳理的本章核心逻辑。你把它存下来,以后写API采集代码时对照着看:
4.6 实战要点总结
| 环节 | 关键操作 | 常见坑点 |
|---|---|---|
| 构造请求 | 用params参数传查询条件 | 忘记URL编码特殊字符 |
| 发送请求 | 设置timeout,加请求头 | 不设超时导致程序卡死 |
| 解析响应 | 用.json()方法,别手动解析 | 直接操作response.text |
| 异常处理 | 分类型捕获,加重试机制 | 裸try-except不区分错误类型 |
好了,这一章的内容就这些。你把这几个要点吃透,以后遇到任何HTTP API采集任务,都能从容应对。记住:先理解RESTful,再写请求,然后解析JSON,最后别忘了异常处理——这四个步骤走下来,数据就到手了。