Python API交互
什么是API?
API(Application Programming Interface,应用程序编程接口)是不同软件系统之间进行通信的一种方式。它允许开发者使用预定义的函数和方法访问其他应用程序、服务或平台的功能,而无需了解其内部实现细节。
在当今的互联网世界中,API已成为构建现代应用不可或缺的工具。通过API,你可以:
- 获取第三方服务的数据(如天气信息、股票价格等)
- 向在线服务发送数据(如发送消息、上传图片等)
- 集成不同的服务和系统
想象API就像餐厅的服务员 - 你(客户)不需要知道厨房(服务器)如何准备食物,你只需要通过服务员(API)下订单并获取结果。
RESTful API基础
REST(Representational State Transfer)是目前最流行的API设计风格。RESTful API使用HTTP协议进行通信,具有以下特点:
-
使用标准的HTTP方法:
- GET:获取资源
- POST:创建资源
- PUT:更新资源
- DELETE:删除资源
-
基于资源的URL结构(如
/users
,/products/123
) -
通常返回JSON或XML格式的数据
Python 中的API交互工具
Python提供了多种库来简化API交互:
- requests:最受欢迎的HTTP库,简单易用
- httpx:支持异步HTTP请求的现代化库
- urllib3:功能强大的低级HTTP客户端
在本教程中,我们将主要使用requests
库,因为它对初学者最友好。
使用requests库进行API交互
安装requests
首先,我们需要安装requests库:
pip install requests
基本GET请求
让我们从一个简单的例子开始,获取一些公开API的数据:
import requests
# 发送GET请求到一个公开API
response = requests.get('https://jsonplaceholder.typicode.com/posts/1')
# 检查请求是否成功
if response.status_code == 200:
# 将JSON响应转换为Python字典
data = response.json()
print("获取的数据:")
print(f"标题: {data['title']}")
print(f"内容: {data['body']}")
else:
print(f"请求失败,状态码: {response.status_code}")
输出示例:
获取的数据:
标题: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
内容: quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto
带参数的GET请求
通常,我们需要在GET请求中发送参数:
import requests
# 定义查询参数
params = {
'userId': 1,
'completed': 'false'
}
# 发送带参数的GET请求
response = requests.get('https://jsonplaceholder.typicode.com/todos', params=params)
# 检查请求是否成功
if response.status_code == 200:
# 将JSON响应转换为Python字典
todos = response.json()
print(f"找到 {len(todos)} 个未完成的待办事项:")
for i, todo in enumerate(todos[:3], 1): # 只显示前3个结果
print(f"{i}. {todo['title']}")
if len(todos) > 3:
print("...")
else:
print(f"请求失败,状态码: {response.status_code}")
输出示例:
找到 10 个未完成的待办事项:
1. delectus aut autem
2. quis ut nam facilis et officia qui
3. fugiat veniam minus
...
POST请求
POST请求用于向服务器发送数据:
import requests
# 要发送的数据
new_post = {
'title': 'Python API交互',
'body': '学习如何使用Python进行API交互',
'userId': 1
}
# 发送POST请求
response = requests.post('https://jsonplaceholder.typicode.com/posts', json=new_post)
# 检查请求是否成功
if response.status_code == 201: # 201表示资源创建成功
created_post = response.json()
print("成功创建新帖子:")
print(f"ID: {created_post['id']}")
print(f"标题: {created_post['title']}")
print(f"创建时间戳: {response.headers.get('date')}")
else:
print(f"请求失败,状态码: {response.status_code}")
输出示例:
成功创建新帖子:
ID: 101
标题: Python API交互
创建时间戳: Wed, 21 Jul 2023 12:34:56 GMT
处理请求头和认证
很多API需要身份验证才能访问。requests库支持多种身份验证方式:
import requests
# 设置请求头
headers = {
'User-Agent': 'Python API教程',
'Authorization': 'Bearer your_access_token_here'
}
# 发送带请求头的GET请求
response = requests.get('https://api.github.com/user', headers=headers)
# 基本身份验证的另一种方式
# response = requests.get('https://api.example.com', auth=('username', 'password'))
print(f"状态码: {response.status_code}")
print(f"响应头: {dict(response.headers)}")
永远不要在代码中硬编码你的API密钥或密码。使用环境变量或配置文件来存储敏感信息。
API请求流程图
下面的流程图展示了一个典型的API交互过程:
错误处理
在与API交互时,良好的错误处理非常重要:
import requests
try:
response = requests.get('https://jsonplaceholder.typicode.com/invalid-endpoint', timeout=5)
# 检查HTTP状态码
response.raise_for_status() # 如果状态码不是2xx,会引发HTTPError异常
# 处理成功的响应
data = response.json()
print("成功:", data)
except requests.exceptions.HTTPError as err:
print(f"HTTP错误: {err}")
except requests.exceptions.ConnectionError:
print("连接错误: 请检查您的网络连接")
except requests.exceptions.Timeout:
print("请求超时: 服务器没有及时响应")
except requests.exceptions.RequestException as err:
print(f"请求错误: {err}")
except ValueError:
print("无效的JSON响应")
实际应用案例
案例1:获取天气信息
下面是一个使用OpenWeatherMap API获取天气信息的示例:
import requests
import os
def get_weather(city):
# 理想情况下,API密钥应存储在环境变量中
api_key = os.environ.get('OPENWEATHER_API_KEY', 'your_api_key_here')
base_url = "https://api.openweathermap.org/data/2.5/weather"
# 设置请求参数
params = {
'q': city,
'appid': api_key,
'units': 'metric' # 使用摄氏度
}
try:
response = requests.get(base_url, params=params)
response.raise_for_status()
weather_data = response.json()
return {
'city': weather_data['name'],
'temperature': weather_data['main']['temp'],
'description': weather_data['weather'][0]['description'],
'humidity': weather_data['main']['humidity']
}
except requests.exceptions.HTTPError as err:
if response.status_code == 404:
return {'error': f"找不到城市: {city}"}
else:
return {'error': f"HTTP错误: {err}"}
except Exception as err:
return {'error': f"发生错误: {err}"}
# 测试函数
if __name__ == "__main__":
city = input("请输入城市名称: ")
result = get_weather(city)
if 'error' in result:
print(result['error'])
else:
print(f"\n{result['city']}的当前天气:")
print(f"温度: {result['temperature']}°C")
print(f"天气状况: {result['description']}")
print(f"湿度: {result['humidity']}%")
可能的输出:
请输入城市名称: 北京
北京的当前天气:
温度: 23.5°C
天气状况: few clouds
湿度: 45%
案例2:创建一个简单的GitHub仓库查询工具
import requests
def get_github_repo_info(username, repo_name):
url = f"https://api.github.com/repos/{username}/{repo_name}"
# GitHub API推荐设置User-Agent头
headers = {
'User-Agent': 'Python-API-Tutorial'
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
repo_data = response.json()
# 提取我们感兴趣的信息
info = {
'name': repo_data['name'],
'description': repo_data['description'],
'stars': repo_data['stargazers_count'],
'forks': repo_data['forks_count'],
'issues': repo_data['open_issues_count'],
'language': repo_data['language'],
'created_at': repo_data['created_at']
}
return info
except requests.exceptions.HTTPError as err:
if response.status_code == 404:
return {'error': f"找不到仓库: {username}/{repo_name}"}
else:
return {'error': f"HTTP错误: {err}"}
except Exception as err:
return {'error': f"发生错误: {err}"}
# 测试函数
if __name__ == "__main__":
username = input("请输入GitHub用户名: ")
repo_name = input("请输入仓库名: ")
repo_info = get_github_repo_info(username, repo_name)
if 'error' in repo_info:
print(repo_info['error'])
else:
print(f"\n仓库: {repo_info['name']}")
print(f"描述: {repo_info['description']}")
print(f"主要语言: {repo_info['language']}")
print(f"星标数: {repo_info['stars']}")
print(f"Fork数: {repo_info['forks']}")
print(f"未解决的Issues: {repo_info['issues']}")
print(f"创建时间: {repo_info['created_at']}")
可能的输出:
请输入GitHub用户名: pandas-dev
请输入仓库名: pandas
仓库: pandas
描述: Flexible and powerful data analysis / manipulation library for Python
主要语言: Python
星标数: 38542
Fork数: 16325
未解决的Issues: 3251
创建时间: 2010-08-24T01:37:33Z
异步API请求
随着应用程序规模的增长,你可能需要同时处理多个API请求。这时候异步请求就派上用场了:
import asyncio
import httpx
async def fetch_data(url):
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.json()
async def main():
# 创建多个并发请求的任务
tasks = [
fetch_data('https://jsonplaceholder.typicode.com/posts/1'),
fetch_data('https://jsonplaceholder.typicode.com/posts/2'),
fetch_data('https://jsonplaceholder.typicode.com/posts/3')
]
# 等待所有任务完成
results = await asyncio.gather(*tasks)
# 打印结果
for i, data in enumerate(results, 1):
print(f"文章 {i}:")
print(f"标题: {data['title']}")
print(f"内容: {data['body'][:50]}...\n")
# 运行异步函数
if __name__ == "__main__":
asyncio.run(main())
异步请求对于需要调用多个API或处理大量请求的应用程序特别有用,可以显著提高性能。
构建API包装器
当你经常使用同一个API时,创建一个API包装器类可以使代码更加整洁和可维护:
import requests
class WeatherAPI:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://api.openweathermap.org/data/2.5"
def get_current_weather(self, city, units='metric'):
"""获取当前天气"""
endpoint = f"{self.base_url}/weather"
params = {
'q': city,
'appid': self.api_key,
'units': units
}
response = requests.get(endpoint, params=params)
response.raise_for_status() # 如果请求失败,引发异常
return response.json()
def get_forecast(self, city, days=5, units='metric'):
"""获取天气预报"""
endpoint = f"{self.base_url}/forecast"
params = {
'q': city,
'appid': self.api_key,
'units': units,
'cnt': days * 8 # 每天8个3小时预报
}
response = requests.get(endpoint, params=params)
response.raise_for_status()
return response.json()
# 使用示例
if __name__ == "__main__":
import os
# 从环境变量获取API密钥
api_key = os.environ.get('OPENWEATHER_API_KEY', 'your_api_key_here')
# 创建API客户端
weather_client = WeatherAPI(api_key)
try:
# 获取当前天气
weather = weather_client.get_current_weather('Shanghai')
print(f"上海当前温度: {weather['main']['temp']}°C")
# 获取天气预报
forecast = weather_client.get_forecast('Shanghai', days=3)
print("\n未来3天天气预报:")
# 处理预报数据...
except requests.exceptions.HTTPError as err:
print(f"API请求错误: {err}")
总结
在本教程中,我们学习了:
- API的基本概念和RESTful API的特点
- 使用Python的requests库进行API交互
- 发送各种类型的HTTP请求(GET、POST等)
- 处理请求头、参数和认证
- 正确处理API请求中的错误
- 通过实际案例展示如何应用API交互
- 异步API请求的基础
- 如何构建API包装器类
API交互是现代Python应用程序的基本技能,掌握这些知识将使你能够构建与外部服务交互的强大应用程序。
练习
-
使用公开的JSONPlaceholder API(https://jsonplaceholder.typicode.com/)完成以下操作:
- 获取所有用户列表
- 获取特定用户的所有帖子
- 创建一个新帖子并打印返回的ID
-
创建一个天气查询程序,允许用户输入城市名称,然后显示当前天气和未来3天的天气预报。
-
构建一个简单的GitHub API包装器,实现以下功能:
- 查询用户信息
- 列出用户的仓库
- 获取特定仓库的贡献者列表
附加资源
- Requests库官方文档
- HTTP状态码参考
- RESTful API设计指南
- Public APIs列表 - 包含许多可以用来练习的免费API
- API安全最佳实践
祝你编程愉快,API交互顺利!