跳到主要内容

Python API交互

什么是API?

API(Application Programming Interface,应用程序编程接口)是不同软件系统之间进行通信的一种方式。它允许开发者使用预定义的函数和方法访问其他应用程序、服务或平台的功能,而无需了解其内部实现细节。

在当今的互联网世界中,API已成为构建现代应用不可或缺的工具。通过API,你可以:

  • 获取第三方服务的数据(如天气信息、股票价格等)
  • 向在线服务发送数据(如发送消息、上传图片等)
  • 集成不同的服务和系统
备注

想象API就像餐厅的服务员 - 你(客户)不需要知道厨房(服务器)如何准备食物,你只需要通过服务员(API)下订单并获取结果。

RESTful API基础

REST(Representational State Transfer)是目前最流行的API设计风格。RESTful API使用HTTP协议进行通信,具有以下特点:

  1. 使用标准的HTTP方法:

    • GET:获取资源
    • POST:创建资源
    • PUT:更新资源
    • DELETE:删除资源
  2. 基于资源的URL结构(如/users/products/123

  3. 通常返回JSON或XML格式的数据

Python 中的API交互工具

Python提供了多种库来简化API交互:

  1. requests:最受欢迎的HTTP库,简单易用
  2. httpx:支持异步HTTP请求的现代化库
  3. urllib3:功能强大的低级HTTP客户端

在本教程中,我们将主要使用requests库,因为它对初学者最友好。

使用requests库进行API交互

安装requests

首先,我们需要安装requests库:

bash
pip install requests

基本GET请求

让我们从一个简单的例子开始,获取一些公开API的数据:

python
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请求中发送参数:

python
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请求用于向服务器发送数据:

python
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库支持多种身份验证方式:

python
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交互时,良好的错误处理非常重要:

python
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获取天气信息的示例:

python
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仓库查询工具

python
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请求。这时候异步请求就派上用场了:

python
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包装器类可以使代码更加整洁和可维护:

python
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}")

总结

在本教程中,我们学习了:

  1. API的基本概念和RESTful API的特点
  2. 使用Python的requests库进行API交互
  3. 发送各种类型的HTTP请求(GET、POST等)
  4. 处理请求头、参数和认证
  5. 正确处理API请求中的错误
  6. 通过实际案例展示如何应用API交互
  7. 异步API请求的基础
  8. 如何构建API包装器类

API交互是现代Python应用程序的基本技能,掌握这些知识将使你能够构建与外部服务交互的强大应用程序。

练习

  1. 使用公开的JSONPlaceholder API(https://jsonplaceholder.typicode.com/)完成以下操作:

    • 获取所有用户列表
    • 获取特定用户的所有帖子
    • 创建一个新帖子并打印返回的ID
  2. 创建一个天气查询程序,允许用户输入城市名称,然后显示当前天气和未来3天的天气预报。

  3. 构建一个简单的GitHub API包装器,实现以下功能:

    • 查询用户信息
    • 列出用户的仓库
    • 获取特定仓库的贡献者列表

附加资源

祝你编程愉快,API交互顺利!