🔎大家好,我是ZTLJQ,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
📝个人主页-ZTLJQ的主页
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝📣系列果你对这个系列感兴趣的话
专栏 - Python从零到企业级应用:短时间成为市场抢手的程序员
✔说明⇢本人讲解主要包括Python爬虫、JS逆向、Python的企业级应用
如果你对这个系列感兴趣的话,可以关注订阅哟👋
为什么需要专门的HTTP库?
Python内置的urllib模块功能强大,但其API相对底层且繁琐。想象一下,为了发送一个带自定义头部和超时设置的POST请求,你需要写上十几行代码...
幸运的是,社区诞生了像requests这样被誉为"人类为人类创造的HTTP库"。它以简洁、优雅的API彻底改变了Python的网络编程格局。
本篇博客将带你从基础到高级,全面掌握requests和它的现代化继任者httpx,并对比它们与urllib的差异。
第一部分:requests - 无可争议的王者
requests (pip install requests) 因其极简的API和强大的功能,成为了事实上的标准。
1.1 基础请求方法
python
import requests
# ---- GET 请求:获取数据 ----
response = requests.get('https://httpbin.org/get')
# 检查响应状态
if response.status_code == 200:
print("请求成功!")
else:
print(f"请求失败,状态码: {response.status_code}")
# 获取响应内容
print(response.text) # 字符串形式
# print(response.content) # 字节形式 (bytes),对于图片等二进制数据有用
# 将JSON响应直接解析为Python字典
json_data = response.json()
print(json_data['url']) # https://httpbin.org/get
# ---- POST 请求:发送数据 ----
# 发送表单数据 (application/x-www-form-urlencoded)
form_data = {'key1': 'value1', 'key2': 'value2'}
post_response = requests.post('https://httpbin.org/post', data=form_data)
# 发送JSON数据 (application/json)
json_payload = {'name': 'Alice', 'age': 30}
post_json_response = requests.post('https://httpbin.org/post', json=json_payload)
# ---- PUT / DELETE 请求 ----
put_response = requests.put('https://httpbin.org/put', json={'data': 'updated'})
delete_response = requests.delete('https://httpbin.org/delete')
解析 :
requests的核心在于每个HTTP方法(get,post,put,delete)都对应一个同名函数,参数直观。
1.2 关键参数详解
python
import requests
# ---- 1. 参数 (params) ----
# 将参数自动附加到URL的查询字符串中
params = {'page': 2, 'size': 10, 'q': 'python tutorial'}
response = requests.get('https://api.example.com/search', params=params)
# 等价于访问: https://api.example.com/search?page=2&size=10&q=python+tutorial
# ---- 2. 自定义头部 (headers) ----
headers = {
'User-Agent': 'MyApp/1.0',
'Authorization': 'Bearer your-jwt-token-here', # Bearer Token 认证
'Content-Type': 'application/json' # 通常由 requests 自动设置
}
response = requests.get('https://api.example.com/data', headers=headers)
# ---- 3. 超时 (timeout) ----
# 非常重要!防止程序无限期等待
try:
response = requests.get('https://slow-website.com', timeout=5) # 5秒后超时
except requests.exceptions.Timeout:
print("请求超时!")
except requests.exceptions.RequestException as e:
print(f"请求出错: {e}")
# ---- 4. 处理重定向 (allow_redirects) ----
# 默认 allow_redirects=True,会自动跟随重定向
# 如果想禁用,设为 False
response = requests.get('http://github.com', allow_redirects=False)
print(response.status_code) # 301
print(response.headers['Location']) # https://github.com
# ---- 5. 会话 (Session) ----
# Session 对象可以跨请求保持 cookies 和 headers,非常高效。
session = requests.Session()
session.headers.update({'User-Agent': 'MyApp/1.0'})
# 登录 (假设这个请求会返回一个 session cookie)
login_data = {'username': 'user', 'password': 'pass'}
session.post('https://example.com/login', data=login_data)
# 后续请求会自动携带登录获得的 cookie
profile_response = session.get('https://example.com/profile')
dashboard_response = session.get('https://example.com/dashboard')
# 最后关闭会话
session.close() # 或使用 with 语句
1.3 实际案例:构建一个简单的REST客户端
python
import requests
from typing import Optional, Dict, Any
class APIClient:
def __init__(self, base_url: str, api_key: str):
self.base_url = base_url.rstrip('/') # 移除末尾斜杠
self.session = requests.Session()
self.session.headers.update({
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
})
def get(self, endpoint: str, params: Optional[Dict] = None) -> Dict[Any, Any]:
"""封装GET请求"""
url = f"{self.base_url}/{endpoint.lstrip('/')}"
try:
response = self.session.get(url, params=params, timeout=10)
response.raise_for_status() # 如果不是2xx状态码,抛出HTTPError
return response.json()
except requests.exceptions.HTTPError as e:
print(f"HTTP错误: {e}")
if e.response.status_code == 404:
print("资源未找到")
elif e.response.status_code == 401:
print("认证失败")
except requests.exceptions.RequestException as e:
print(f"请求异常: {e}")
return {}
def post(self, endpoint: str, data: Dict) -> Dict[Any, Any]:
"""封装POST请求"""
url = f"{self.base_url}/{endpoint.lstrip('/')}"
try:
response = self.session.post(url, json=data, timeout=10)
response.raise_for_status()
return response.json() # 假设服务器返回创建的资源
except Exception as e:
print(f"POST请求失败: {e}")
return {}
def close(self):
"""关闭会话"""
self.session.close()
# 使用客户端
client = APIClient("https://jsonplaceholder.typicode.com", "dummy-key")
# 获取用户列表
users = client.get("/users")
for user in users[:2]: # 打印前两个
print(user['name'])
# 创建一个新帖子
new_post = client.post("/posts", {
"title": "My New Post",
"body": "This is the content.",
"userId": 1
})
print("创建的帖子:", new_post)
# 别忘了关闭
client.close()
解析 : 这个案例展示了如何利用
Session和良好的错误处理来构建一个健壮、可复用的API客户端。
第二部分:httpx - 现代化的全能选手
httpx (pip install httpx) 是一个现代化的HTTP客户端,旨在成为requests的替代品,同时增加了许多激动人心的新特性。
2.1 同步与异步支持
这是httpx最大的亮点。你可以用几乎相同的API编写同步和异步代码。
python
import httpx
import asyncio
# ---- 同步模式 (类似 requests) ----
def sync_example():
response = httpx.get('https://httpbin.org/get')
print(response.status_code)
print(response.json()['url'])
sync_example()
# ---- 异步模式 (async/await) ----
async def async_example():
async with httpx.AsyncClient() as client:
response = await client.get('https://httpbin.org/get')
print(response.status_code)
print(response.json()['url'])
# 运行异步函数
asyncio.run(async_example())
优势: 异步I/O可以在等待网络响应时释放控制权,执行其他任务,极大地提高了I/O密集型应用(如爬虫、API聚合器)的并发性能。
2.2 HTTP/2 支持
httpx原生支持HTTP/2协议,可以更高效地复用连接,减少延迟。
python
import httpx
# 默认情况下,如果服务器支持,httpx 会协商使用 HTTP/2
with httpx.Client(http2=True) as client:
response = client.get('https://http2.golang.org')
print(f"HTTP Version: {response.http_version}") # HTTP/2
2.3 实际案例:高效的异步爬虫
python
1import httpx
2import asyncio
3from bs4 import BeautifulSoup
4
5# 我们要抓取的多个URL
6urls = [
7 'https://httpbin.org/delay/1',
8 'https://httpbin.org/delay/2',
9 'https://httpbin.org/delay/1',
10]
11
12async def fetch_title(client: httpx.AsyncClient, url: str) -> str:
13 """异步获取单个页面的标题"""
14 try:
15 response = await client.get(url, timeout=10)
16 response.raise_for_status()
17
18 # 使用 BeautifulSoup 解析HTML
19 soup = BeautifulSoup(response.text, 'html.parser')
20 title_tag = soup.find('title')
21 title = title_tag.get_text(strip=True) if title_tag else "No Title"
22
23 return f"{url}: {title}"
24 except Exception as e:
25 return f"{url}: Error - {e}"
26
27async def main():
28 # 创建一个共享的异步客户端
29 async with httpx.AsyncClient() as client:
30 # 使用 asyncio.gather 并发执行所有请求
31 tasks = [fetch_title(client, url) for url in urls]
32 results = await asyncio.gather(*tasks)
33
34 for result in results:
35 print(result)
36
37# 运行主协程
38asyncio.run(main())
解析: 在同步版本中,抓取这三个URL至少需要1+2+1=4秒。而在异步版本中,由于是并发请求,总时间大约只有2秒多一点,性能提升显著。
第三部分:与 urllib 的对比
了解urllib有助于理解底层原理。
python
# 使用 urllib 发送一个带参数和头部的GET请求
from urllib import request, parse
base_url = 'https://httpbin.org/get'
params = {'key': 'value'}
query_string = parse.urlencode(params)
full_url = f"{base_url}?{query_string}"
req = request.Request(
full_url,
headers={
'User-Agent': 'MyApp/1.0'
}
)
try:
with request.urlopen(req, timeout=5) as response:
data = response.read().decode('utf-8') # 必须手动解码
print(data)
except Exception as e:
print(f"Error: {e}")
对比:
- 代码量 :
urllib需要更多样板代码。- 易用性 :
requests/httpx的API远胜一筹。- 功能 :
requests/httpx内置了JSON处理、会话管理、文件上传等高级功能。- 学习成本 :
requests几乎是零成本入门。
第四部分:最佳实践与陷阱
- 始终设置
timeout: 这是最重要的实践,防止程序挂起。 - 善用
Session/Client: 对于多次请求,复用连接能显著提升性能。 - 检查状态码 : 不要只依赖
try-except,主动检查status_code或使用raise_for_status()。 - 处理异常 : 捕获
RequestException及其子类(ConnectionError,Timeout,HTTPError)。 - 管理连接 : 使用
with语句确保Session或Client被正确关闭。 - 考虑异步 : 当需要高并发时(如爬取大量页面),
httpx的异步模式是更好的选择。 - 安全: 不要在代码中硬编码敏感信息(如API密钥)。使用环境变量或配置文件。
结语
requests重新定义了Python的HTTP体验,而httpx则在此基础上引领我们走向异步和HTTP/2的未来。
通过本篇博客的学习,你应该已经掌握了:
- 如何使用
requests进行各种HTTP操作,并构建健壮的客户端。 httpx的强大功能,特别是其异步和HTTP/2支持。- 如何根据项目需求选择合适的库。
- 至关重要的性能和安全最佳实践。
