Python(3)--Requests库学习文档
Requests库学习文档
📚 文档概述
本文档整合了Requests库从零开始的学习内容,包括基础概念、实践代码、常见问题及解答,方便后续复习和查阅。
1. Requests库基础介绍
1.1 什么是Requests库?
import requests
# Requests是Python中最流行的HTTP库,用于发送各种HTTP请求
# 替代了Python内置的urllib,提供更简洁直观的API
1.2 与urllib对比的优势
# urllib写法(复杂)
import urllib.request
import urllib.parse
data = urllib.parse.urlencode({'key': 'value'}).encode()
req = urllib.request.Request('http://httpbin.org/post', data=data)
response = urllib.request.urlopen(req)
# Requests写法(简洁)
response = requests.post('http://httpbin.org/post', data={'key': 'value'})
# 优势总结:
# 1. 语法更简洁直观
# 2. 自动处理编码
# 3. 更好的错误处理
# 4. 更完善的功能
1.3 安装
pip install requests
2. GET请求详解
2.1 基础GET请求
import requests
# 最简单的GET请求
response = requests.get('https://jsonplaceholder.typicode.com/posts/1')
print(response.status_code) # 状态码
print(response.text) # 响应内容
# 为什么要检查status_code?
# 因为网络请求可能失败,需要知道请求状态
2.2 带参数的GET请求
# 方法1:直接在URL中添加参数(不推荐)
response = requests.get('https://jsonplaceholder.typicode.com/posts?userId=1')
# 方法2:使用params参数(推荐)
params = {
'userId': 1,
'_limit': 5
}
response = requests.get('https://jsonplaceholder.typicode.com/posts', params=params)
print(response.url) # 查看最终请求的URL
print(response.json()) # 将响应解析为JSON
# 为什么用params而不是手动拼接URL?
# 1. 自动URL编码(处理特殊字符)
# 2. 更清晰的代码结构
# 3. 自动处理数组等复杂参数
3. POST请求详解
3.1 基础POST请求
# 表单数据POST
data = {
'title': '测试文章',
'body': '这是测试内容',
'userId': 1
}
response = requests.post('https://jsonplaceholder.typicode.com/posts', data=data)
# JSON数据POST
json_data = {
'user': {
'name': 'Alice',
'email': 'alice@example.com'
}
}
response = requests.post('https://jsonplaceholder.typicode.com/posts', json=json_data)
# 为什么区分data和json参数?
# data:发送表单格式数据(application/x-www-form-urlencoded)
# json:发送JSON格式数据(application/json)
# 服务器根据Content-Type头来解析数据
3.2 文件上传
# 上传文件
files = {'file': open('example.txt', 'rb')}
response = requests.post('https://httpbin.org/post', files=files)
# 为什么用'rb'模式打开文件?
# 'rb'表示以二进制只读模式打开,确保文件内容不被修改,适合网络传输
4. Headers详解
4.1 为什么要设置Headers?
# 带自定义Headers的请求
headers = {
'User-Agent': 'MyApp/1.0', # 标识客户端类型
'Authorization': 'Bearer your_token', # 身份验证
'Content-Type': 'application/json', # 告诉服务器数据格式
'Accept': 'application/json' # 告诉服务器期望的响应格式
}
response = requests.get('https://httpbin.org/user-agent', headers=headers)
# Headers的作用:
# 1. 身份验证(Authorization)
# 2. 内容协商(Accept, Content-Type)
# 3. 客户端信息(User-Agent)
# 4. 缓存控制(Cache-Control)
# 5. Cookies管理
4.2 Content-Type详解
# Content-Type = "我发给你的数据是什么格式,请你按这个格式来解析"
# 常见的Content-Type类型:
content_types = {
'application/x-www-form-urlencoded': 'HTML表单数据',
'application/json': 'JSON格式数据',
'multipart/form-data': '文件上传表单',
'text/plain': '纯文本数据',
'application/xml': 'XML格式数据'
}
# 实践:正确设置Content-Type
def user_registration():
"""用户注册(表单数据)"""
form_data = {
'username': 'new_user',
'email': 'user@example.com',
'password': 'secure_password'
}
response = requests.post(
'https://httpbin.org/post',
data=form_data,
headers={'Content-Type': 'application/x-www-form-urlencoded'}
)
return response
def create_product():
"""创建产品(JSON数据)"""
product_data = {
'product': {
'name': '智能手机',
'price': 2999.99,
'specifications': {
'screen': '6.5英寸',
'memory': '8GB'
}
}
}
response = requests.post(
'https://httpbin.org/post',
json=product_data # 自动设置Content-Type为application/json
)
return response
4.3 response.headers.get()方法详解
response = requests.get('https://jsonplaceholder.typicode.com/posts/1')
# 基本语法:response.headers.get(key, default=None)
content_type = response.headers.get('Content-Type')
print(f"Content-Type: {content_type}")
# 如果头部不存在,返回None(不会报错)
non_existent = response.headers.get('Non-Existent-Header')
print(f"不存在的头部: {non_existent}") # 输出: None
# 可以设置默认值
non_existent_with_default = response.headers.get('Non-Existent-Header', '默认值')
print(f"带默认值的头部: {non_existent_with_default}") # 输出: 默认值
# 为什么使用.get()而不是直接访问?
# 1. 避免KeyError异常
# 2. 代码更简洁
# 3. 可以设置默认值
# 4. 更符合Python的"请求原谅比请求许可更容易"哲学
5. 响应处理
5.1 响应头和响应体分离的原因
response = requests.get('https://jsonplaceholder.typicode.com/posts/1')
# 响应头
print("=== 响应头 ===")
for key, value in response.headers.items():
print(f"{key}: {value}")
# 响应体
print("\n=== 响应体 ===")
print(response.text)
# 为什么需要这种分离设计?
# 设计哲学:元数据 vs 实际数据
# 类比:响应头 = 快递单,响应体 = 快递包裹里的实际物品
5.2 响应头体的分离优势
def analyze_response(response):
"""分析响应结构"""
print("📦 快递单信息(响应头):")
print(f" 快递公司: {response.headers.get('Server', 'Unknown')}")
print(f" 包裹类型: {response.headers.get('Content-Type', 'Unknown')}")
print(f" 包裹大小: {response.headers.get('Content-Length', 'Unknown')} 字节")
print("\n🎁 包裹内容(响应体):")
print(f" 实际物品: {response.text[:100]}...")
# 分离的优势:
# 1. 性能优化:客户端可以先读取头部决定如何处理,无需解析整个响应
# 2. 功能分离:头部处理控制信息,体部承载实际数据
# 3. 缓存效率:缓存系统只需读取头部即可决定缓存策略
# 4. 安全扫描:安全设备可以快速检查头部而不必解析内容
# 5. 协议扩展:通过添加新的头部字段来扩展功能,不影响现有数据格式
6. POST请求中表单数据和JSON数据的场景区分
6.1 基础概念对比
# 表单数据 (application/x-www-form-urlencoded)
form_data = {
'username': 'john_doe',
'password': 'secret123',
'remember_me': '1'
}
# JSON数据 (application/json)
json_data = {
'user': {
'username': 'john_doe',
'profile': {
'age': 25,
'preferences': ['music', 'sports']
}
}
}
6.2 场景决策指南
def smart_data_selector(scenario_description, data_structure):
"""智能选择使用data还是json参数"""
print(f"\n场景分析: {scenario_description}")
# 分析数据结构特征
has_nesting = any(isinstance(v, (dict, list)) for v in data_structure.values())
has_special_types = any(isinstance(v, (bool, int, float, list, dict))
for v in data_structure.values())
# 决策逻辑
if has_nesting or has_special_types:
recommendation = "json"
reason = "数据结构复杂,包含嵌套或特殊类型"
else:
recommendation = "data"
reason = "简单键值对,适合表单格式"
print(f"推荐使用: {recommendation}参数")
print(f"原因: {reason}")
return recommendation
# 测试不同场景
test_scenarios = [
("用户登录", {"username": "john", "password": "secret", "remember_me": True}),
("创建产品", {"product": {"name": "Laptop", "price": 999.99, "tags": ["tech"]}}),
("搜索过滤", {"category": "electronics", "price_min": 100, "price_max": 500}),
]
for scenario, data in test_scenarios:
smart_data_selector(scenario, data)
6.3 具体行业场景
# 电子商务场景
def ecommerce_scenarios():
"""电子商务场景分析"""
# 添加到购物车 → 表单数据
add_to_cart_form = {
'product_id': '12345',
'quantity': '2',
'variant': 'blue-large'
}
# 创建完整订单 → JSON数据
create_order_json = {
'order': {
'customer_id': 'cust_789',
'items': [
{
'product_id': '12345',
'quantity': 2,
'price': 29.99,
'options': {'color': 'blue', 'size': 'L'}
}
]
}
}
return add_to_cart_form, create_order_json
# 社交媒体场景
def social_media_scenarios():
"""社交媒体场景分析"""
# 点赞操作 → 表单数据
like_form = {
'post_id': 'post_123',
'action': 'like',
'user_id': 'user_456'
}
# 发布复杂帖子 → JSON数据
create_post_json = {
'post': {
'author_id': 'user_456',
'content': {
'text': 'Check out this amazing photo!',
'mentions': ['@user123', '@user789'],
'hashtags': ['#python', '#coding']
}
}
}
return like_form, create_post_json
6.4 技术栈决定数据格式
# 传统技术栈 → 表单数据
traditional_tech = {
'backend': ['PHP', 'Laravel', 'Django', 'Ruby on Rails'],
'前端': '服务器渲染模板',
'数据格式': '表单数据 (data)',
'示例': '用户注册、登录、搜索过滤'
}
# 现代技术栈 → JSON数据
modern_tech = {
'backend': ['Node.js', 'FastAPI', 'Spring Boot', 'GraphQL'],
'前端': ['React', 'Vue', 'Angular', '移动App'],
'数据格式': 'JSON数据 (json)',
'示例': 'RESTful API、微服务、移动后端'
}
7. 错误处理和最佳实践
7.1 完整的错误处理
def robust_request(url, method='GET', **kwargs):
"""
健壮的请求函数,包含完整的错误处理
"""
try:
if method.upper() == 'GET':
response = requests.get(url, **kwargs)
elif method.upper() == 'POST':
response = requests.post(url, **kwargs)
else:
raise ValueError(f"不支持的HTTP方法: {method}")
# 如果状态码不是200,引发HTTPError异常
response.raise_for_status()
return response
except requests.exceptions.HTTPError as e:
print(f"HTTP错误: {e}")
except requests.exceptions.ConnectionError as e:
print(f"连接错误: {e}")
except requests.exceptions.Timeout as e:
print(f"超时错误: {e}")
except requests.exceptions.RequestException as e:
print(f"请求异常: {e}")
except Exception as e:
print(f"未知错误: {e}")
# 使用示例
response = robust_request(
'https://jsonplaceholder.typicode.com/posts/1',
timeout=5
)
7.2 API监控工具
class APIMonitor:
def __init__(self):
self.session = requests.Session()
def check_api_health(self, url):
"""检查API健康状况,分析响应头"""
try:
response = self.session.get(url, timeout=10)
health_info = {
'url': url,
'status_code': response.status_code,
'response_time': response.elapsed.total_seconds(),
'headers': {
'server': response.headers.get('Server', 'Unknown'),
'content_type': response.headers.get('Content-Type', 'Unknown'),
'content_length': response.headers.get('Content-Length', 'Unknown'),
},
'is_healthy': 200 <= response.status_code < 300
}
return health_info
except requests.exceptions.RequestException as e:
return {
'url': url,
'error': str(e),
'is_healthy': False
}
8. 综合实践项目
8.1 GitHub用户信息查询
def github_user_info(username):
"""
获取GitHub用户信息的完整示例
"""
headers = {
'User-Agent': 'PythonLearningApp/1.0',
'Accept': 'application/vnd.github.v3+json'
}
url = f'https://api.github.com/users/{username}'
try:
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
user_data = response.json()
print(f"用户名: {user_data['login']}")
print(f"姓名: {user_data.get('name', '未设置')}")
print(f"粉丝数: {user_data['followers']}")
return user_data
elif response.status_code == 404:
print(f"错误:用户 '{username}' 不存在")
else:
print(f"HTTP错误: {response.status_code}")
except requests.exceptions.Timeout:
print("请求超时,请检查网络连接")
except requests.exceptions.ConnectionError:
print("网络连接错误")
except requests.exceptions.RequestException as e:
print(f"请求异常: {e}")
# 测试
github_user_info('octocat')
8.2 智能API客户端
class SmartAPIClient:
def __init__(self, base_url):
self.base_url = base_url
self.session = requests.Session()
def make_request(self, endpoint, method='GET', **kwargs):
"""智能API请求,充分利用头部信息"""
url = f"{self.base_url}/{endpoint}"
response = self.session.request(method, url, **kwargs)
# 根据Content-Type自动选择解析方式
return self._parse_response(response)
def _parse_response(self, response):
"""根据Content-Type智能解析响应体"""
content_type = response.headers.get('Content-Type', '')
if 'application/json' in content_type:
return response.json()
elif 'text/html' in content_type or 'text/plain' in content_type:
return response.text
elif 'image/' in content_type:
return response.content
else:
return response.content
# 使用示例
client = SmartAPIClient('https://jsonplaceholder.typicode.com')
result = client.make_request('posts/1')
print(f"解析结果: {result}")
9. 关键概念总结
9.1 GET vs POST
- GET:获取数据,参数在URL中,用
params - POST:提交数据,数据在请求体中,用
data或json
9.2 data vs json 参数
- data:表单格式,简单键值对
- json:JSON格式,复杂嵌套数据结构
9.3 Headers核心作用
- Content-Type:告诉服务器你发送的数据格式
- Authorization:身份验证
- User-Agent:客户端标识
- Accept:期望的响应格式
9.4 响应处理
- 响应头:元数据信息(状态、内容类型、缓存等)
- 响应体:实际数据内容
10. 常见问题解答
Q: 为什么POST请求不用params,反而用data和json?
A: 这是由HTTP协议设计决定的:
- GET请求参数在URL中,适合获取数据和简单参数
- POST请求数据在请求体中,更适合提交复杂数据和敏感信息
- data用于表单格式,json用于JSON格式
Q: response.headers.get()方法怎么用?
A:
# 语法:response.headers.get(key, default=None)
content_type = response.headers.get('Content-Type')
server = response.headers.get('Server', 'Unknown') # 设置默认值
# 优势:避免KeyError,代码更健壮
Q: 表单数据和JSON数据如何选择?
A: 根据数据结构和应用场景:
- 表单数据:简单键值对,传统Web应用
- JSON数据:复杂嵌套结构,现代API
Q: Content-Type的作用是什么?
A: Content-Type告诉服务器"我发给你的数据是什么格式,请你按这个格式来解析"
📝 学习建议
- 多实践:在实际项目中应用这些概念
- 查看文档:遇到问题先查看官方文档
- 使用调试工具:利用浏览器开发者工具观察网络请求
- 错误处理:始终包含完整的错误处理逻辑
- 遵循最佳实践:根据场景选择合适的数据格式和方法
本文档根据实际学习过程整理,涵盖Requests库的核心概念和实践技巧,适合随时复习查阅。

浙公网安备 33010602011771号