前言
Python 的 requests 库是 Python 生态中最受欢迎的第三方 HTTP 库,被誉为”给人类使用的 HTTP 库”。无论是调用 RESTful API、爬取网页数据,还是实现自动化办公中的网络请求,requests 都是首选工具。本教程将从安装开始,带你一步步掌握 requests 库的核心用法,包含大量可直接运行的代码示例。
1. 安装与环境准备
requests 库的安装非常简单,一行命令即可搞定:
pip install requests
验证安装是否成功:
import requests
print(requests.__version__) # 输出示例:2.31.0
建议搭配 venv 虚拟环境使用,避免与全局包冲突:
python -m venv myenv
source myenv/bin/activate # Linux/macOS
myenv\Scripts\activate # Windows
pip install requests
2. 发送 GET 请求
GET 请求是最基本的 HTTP 方法,用于获取资源。requests 库让 GET 请求变得极其简洁:
import requests
# 最简单的 GET 请求
response = requests.get('https://api.github.com')
print(response.status_code) # 200
print(response.text[:200]) # 响应内容的前200个字符
带参数的 GET 请求
通过 params 参数传递 URL 查询参数,requests 会自动编码:
import requests
# 搜索 GitHub 上的 Python 仓库
url = 'https://api.github.com/search/repositories'
params = {
'q': 'language:python',
'sort': 'stars',
'per_page': 3
}
response = requests.get(url, params=params)
data = response.json()
for repo in data['items']:
print(f"{repo['full_name']} - ⭐ {repo['stargazers_count']}")
# 输出示例:
# tensorflow/tensorflow - ⭐ 188000+
# django/django - ⭐ 82000+
# pallets/flask - ⭐ 69000+
自定义请求头
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'application/json',
'Authorization': 'Bearer your_token_here'
}
response = requests.get('https://api.github.com/user', headers=headers)
print(response.json())
3. 发送 POST 请求
POST 请求用于向服务器提交数据,比如创建资源、提交表单等:
import requests
# 发送 JSON 数据(最常见的场景)
url = 'https://jsonplaceholder.typicode.com/posts'
data = {
'title': 'Python requests 教程',
'body': '这是一篇关于 requests 库的教程',
'userId': 1
}
response = requests.post(url, json=data)
print(f"状态码: {response.status_code}") # 201 Created
print(f"创建的资源 ID: {response.json()['id']}") # 101
发送表单数据
import requests
# 模拟表单提交
url = 'https://httpbin.org/post'
form_data = {'username': 'admin', 'password': 'secret123'}
response = requests.post(url, data=form_data)
print(response.json()['form'])
# 输出: {'username': 'admin', 'password': 'secret123'}
上传文件
import requests
# 上传单个文件
files = {'file': open('report.xlsx', 'rb')}
response = requests.post('https://httpbin.org/post', files=files)
print(response.json()['files'])
# 上传多个文件
files = {
'file1': ('report.pdf', open('report.pdf', 'rb'), 'application/pdf'),
'file2': ('image.png', open('image.png', 'rb'), 'image/png')
}
response = requests.post('https://httpbin.org/post', files=files)
4. Session 会话管理
Session 对象可以跨请求保持 cookies 和请求头,是登录态爬虫和 API 调用的核心工具:
import requests
# 创建 Session 对象
session = requests.Session()
# 设置全局请求头 —— 所有通过此 session 发起的请求都会携带
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
})
# 先登录(假设一个登录接口)
login_url = 'https://httpbin.org/post'
login_data = {'username': 'testuser', 'password': '123456'}
session.post(login_url, data=login_data)
# 后续请求自动携带登录后的 cookies
profile = session.get('https://httpbin.org/cookies')
print(profile.json()) # 包含登录后的 cookie 信息
# 关闭 Session
session.close()
# 推荐使用上下文管理器,自动关闭
with requests.Session() as s:
s.get('https://httpbin.org/get')
# 自动关闭连接
Session 的典型应用场景
import requests
# 模拟知乎登录后的爬取
session = requests.Session()
session.headers.update({'User-Agent': 'Mozilla/5.0'})
# 第一步:获取登录页面,提取 XSRF token
login_page = session.get('https://www.zhihu.com/signin')
# ... 解析 token(简化处理)
# 第二步:提交登录
session.post('https://www.zhihu.com/api/v3/oauth/sign_in',
json={'username': 'xxx', 'password': 'xxx'})
# 第三步:用同一 session 访问需要登录的页面
response = session.get('https://www.zhihu.com/api/v4/me')
print(response.status_code) # 200 表示已登录成功
5. 响应处理详解
requests 返回的 Response 对象提供了丰富的属性和方法:
import requests
response = requests.get('https://api.github.com')
# 常用属性
print(f"状态码: {response.status_code}") # 200
print(f"响应头: {response.headers['Content-Type']}") # application/json; charset=utf-8
print(f"编码: {response.encoding}") # utf-8
print(f"请求耗时: {response.elapsed.total_seconds():.3f}s") # 0.452s
# 常用方法
print(response.text) # 原始字符串响应体
print(response.content) # 二进制响应体(适合图片/文件)
print(response.json()) # 解析为 JSON 字典(最常用)
# 检查响应状态
print(response.ok) # True (status_code < 400)
print(response.is_redirect) # 是否为重定向
print(response.url) # 最终的 URL(跟踪重定向后)
6. 超时与错误处理
生产环境一定要设置超时,否则请求可能永久挂起:
import requests
from requests.exceptions import RequestException, Timeout, ConnectionError
try:
# 设置超时:连接超时3秒,读取超时10秒
response = requests.get('https://httpbin.org/delay/5',
timeout=(3, 10))
response.raise_for_status() # 状态码非200时抛出 HTTPError
print(response.json())
except Timeout:
print("❌ 请求超时,请检查网络或目标服务器")
except ConnectionError:
print("❌ 连接失败,目标服务器不可达")
except RequestException as e:
print(f"❌ 请求错误: {e}")
# 更简洁的处理方式
try:
resp = requests.get('https://api.github.com', timeout=10)
resp.raise_for_status()
except Exception as e:
print(f"请求失败: {e}")
else:
print(f"✅ 请求成功,状态码: {resp.status_code}")
7. 请求重试与适配器
使用 HTTPAdapter 可以设置自动重试,应对网络波动:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# 创建 Session
session = requests.Session()
# 配置重试策略
retry_strategy = Retry(
total=3, # 最多重试3次
backoff_factor=1, # 重试间隔:1s, 2s, 4s
status_forcelist=[500, 502, 503, 504], # 哪些状态码触发重试
allowed_methods=['GET', 'POST'] # 哪些方法可以重试
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount('https://', adapter)
session.mount('http://', adapter)
# 即使服务器返回 503,也会自动重试
response = session.get('https://httpbin.org/status/503')
print(f"最终状态码: {response.status_code}")
8. 实战:天气 API 查询助手
综合运用以上知识,编写一个命令行天气查询工具:
import requests
from datetime import datetime
def get_weather(city: str, api_key: str = "demo_key"):
"""查询指定城市的实时天气"""
url = "https://api.openweathermap.org/data/2.5/weather"
params = {
'q': city,
'appid': api_key,
'units': 'metric', # 摄氏度
'lang': 'zh_cn'
}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
weather_info = {
'城市': data['name'],
'天气': data['weather'][0]['description'],
'温度': f"{data['main']['temp']}°C",
'体感温度': f"{data['main']['feels_like']}°C",
'湿度': f"{data['main']['humidity']}%",
'风速': f"{data['wind']['speed']} m/s",
'更新时间': datetime.fromtimestamp(data['dt']).strftime('%Y-%m-%d %H:%M')
}
print(f"\n🌤️ {city} 实时天气报告")
print("=" * 30)
for key, value in weather_info.items():
print(f"{key}: {value}")
except requests.exceptions.HTTPError as e:
print(f"❌ HTTP 错误: {e}")
except requests.exceptions.ConnectionError:
print("❌ 无法连接到天气服务器,请检查网络")
except requests.exceptions.Timeout:
print("❌ 请求超时")
except Exception as e:
print(f"❌ 未知错误: {e}")
if __name__ == '__main__':
get_weather('Beijing')
9. 常见问题与避坑指南
# ❌ 常见错误1:忘记设置编码导致乱码
response = requests.get('https://example.com')
# response.encoding 可能为 ISO-8859-1
# ✅ 解决方法:手动指定编码
response.encoding = 'utf-8'
print(response.text)
# ❌ 常见错误2:未设置 User-Agent 被反爬
response = requests.get('https://some-website.com')
# 返回 403 或空内容
# ✅ 解决方法:模拟浏览器头
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
response = requests.get('https://some-website.com', headers=headers)
# ❌ 常见错误3:忘记设置 timeout 导致程序卡死
response = requests.get('https://slow-server.com') # 可能卡住几分钟
# ✅ 解决方法:始终设置超时
response = requests.get('https://slow-server.com', timeout=5)
FAQ(常见问题)
Q1:requests 和 urllib 有什么区别?哪个更好?
A:requests 是基于 urllib3 的高级封装,API 设计更人性化。具体对比:requests 一行代码搞定 GET 请求(requests.get()),而 urllib 需要 urllib.request.urlopen() + 额外处理。requests 自动处理 JSON 解析、Session 管理、连接池、SSL 验证等。除非有特殊需求,否则优先使用 requests。
Q2:为什么 requests.get() 返回的是乱码?
A:requests 会从响应头 Content-Type 猜测编码,但有些网站返回的 charset 不正确。解决方法:response.encoding = 'utf-8' 或 response.apparent_encoding(基于内容自动检测)。建议显示指定 encoding='utf-8'。
Q3:使用 Session 时,什么时候需要手动关闭连接?
A:使用上下文管理器(with requests.Session() as s:)时不需要手动关闭,程序退出时自动释放。如果手动创建 Session,建议用完调用 session.close()。另外,Session 会保存 cookies 和连接池,频繁创建新 Session 而不是复用会导致性能下降,推荐在需要登录态保持的场景下始终使用 Session。