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就够了,其他后面慢慢来。

核心要点:环境数据采集99%的场景只用GET方法——我们只是去拿数据,不修改服务器上的任何东西。

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()方法,既安全又省心。

我的小技巧:拿到API返回后,先打印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采集代码时对照着看:

HTTP API数据采集核心流程 1. 理解RESTful API 资源 + URL + HTTP方法 2. 构造HTTP请求 URL + 参数 + 请求头 3. 发送请求 requests.get() 成功? 4. 解析JSON响应 response.json() 5. 提取目标字段 data['key']['subkey'] 异常处理 • 超时异常 • HTTP错误 • 连接错误 • 重试机制 • 限流处理

4.6 实战要点总结

环节 关键操作 常见坑点
构造请求 用params参数传查询条件 忘记URL编码特殊字符
发送请求 设置timeout,加请求头 不设超时导致程序卡死
解析响应 用.json()方法,别手动解析 直接操作response.text
异常处理 分类型捕获,加重试机制 裸try-except不区分错误类型

好了,这一章的内容就这些。你把这几个要点吃透,以后遇到任何HTTP API采集任务,都能从容应对。记住:先理解RESTful,再写请求,然后解析JSON,最后别忘了异常处理——这四个步骤走下来,数据就到手了。


专注资料整理