网络请求
本教程共 70 篇 · 第 53 篇 · 更新于 2026-07-22 · 约 5 分钟阅读
53. 网络请求
本节目标:学会用
urllib发送基础 HTTP 请求,掌握requests库的高级用法,理解状态码、请求头和会话的概念。
现代程序很少孤立运行,几乎都要跟网络打交道:调用 API、下载文件、发送 webhook。Python 提供了标准库的 urllib 和第三方库 requests 两种方式来发送 HTTP 请求。
urllib:标准库方案
urllib 是 Python 内置的网络请求工具,不需要额外安装:
from urllib import request
# 最简单的 GET 请求
resp = request.urlopen('https://api.github.com')
print(resp.status) # 200
print(resp.read().decode('utf-8'))
添加请求头
很多 API 要求提供 User-Agent 或其他头部:
from urllib import request
req = request.Request(
'https://api.github.com',
headers={'User-Agent': 'Mozilla/5.0'}
)
resp = request.urlopen(req)
发送 POST 请求
from urllib import request, parse
data = parse.urlencode({'name': 'Alice', 'age': '25'}).encode('utf-8')
req = request.Request('https://httpbin.org/post', data=data, method='POST')
resp = request.urlopen(req)
print(resp.read().decode('utf-8'))
Note
urllib功能完整,但 API 设计偏底层。每次请求都要手动处理编码、头部、错误处理,代码比较啰嗦。日常开发中,大部分开发者会选择requests。
requests:更人性化的选择
requests 是 Python 社区最受欢迎的 HTTP 库,口号是「HTTP for Humans」。
安装:
pip install requests
基础请求
import requests
# GET
resp = requests.get('https://api.github.com')
print(resp.status_code) # 200
print(resp.text) # 响应文本
print(resp.json()) # 直接解析 JSON
# 带参数
resp = requests.get('https://httpbin.org/get', params={'key': 'value'})
print(resp.url) # https://httpbin.org/get?key=value
# POST
resp = requests.post(
'https://httpbin.org/post',
data={'name': 'Alice'}
)
Tip
requests会自动处理 URL 编码、JSON 解析、字符集检测。返回的Response对象封装了状态码、头部、内容等所有信息。
请求头和 JSON 数据
import requests
headers = {
'User-Agent': 'MyApp/1.0',
'Authorization': 'Bearer token123'
}
resp = requests.post(
'https://api.example.com/users',
headers=headers,
json={'name': 'Alice', 'age': 25} # 自动序列化为 JSON
)
print(resp.headers.get('Content-Type'))
上传文件
with open('photo.jpg', 'rb') as f:
resp = requests.post(
'https://httpbin.org/post',
files={'file': f}
)
超时设置
网络请求可能卡住,永远设置超时:
try:
resp = requests.get('https://slow.site.com', timeout=5)
except requests.Timeout:
print('请求超时')
timeout 参数可以是 (连接超时, 读取超时) 的元组,也可以是一个总秒数。
Warning不写
timeout的请求,在网络异常时可能挂起几十分钟。这是生产环境的大坑,务必养成设置超时的好习惯。
使用 Session
如果多个请求需要共享 cookie、头部或连接池,用 Session:
import requests
session = requests.Session()
session.headers.update({'User-Agent': 'MyApp/1.0'})
# 登录后 cookie 自动保持
session.post('https://api.example.com/login', json={'user': 'alice'})
# 后续请求自动带上 cookie
resp = session.get('https://api.example.com/profile')
Session 还会复用底层 TCP 连接,发送多个请求到同一主机时性能更好。
状态码和异常处理
import requests
resp = requests.get('https://httpbin.org/status/404')
print(resp.status_code) # 404
# 如果状态码 >= 400,抛 HTTPError
resp.raise_for_status()
常用状态码:
| 状态码 | 含义 |
|---|---|
| 200 | 成功 |
| 301/302 | 重定向 |
| 400 | 请求参数错误 |
| 401 | 未授权 |
| 403 | 禁止访问 |
| 404 | 资源不存在 |
| 500 | 服务器内部错误 |
| 502/503 | 网关/服务不可用 |
实战:下载文件并显示进度
import requests
url = 'https://example.com/large.zip'
resp = requests.get(url, stream=True)
resp.raise_for_status()
total = int(resp.headers.get('content-length', 0))
downloaded = 0
with open('large.zip', 'wb') as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
downloaded += len(chunk)
if total:
percent = downloaded / total * 100
print(f"\r下载进度: {percent:.1f}%", end='')
print("\n下载完成")
stream=True 让响应内容逐块读取,避免大文件一次性载入内存。iter_content() 返回指定大小的数据块。
urllib vs requests:怎么选
| 场景 | 推荐 |
|---|---|
| 不能安装第三方依赖 | urllib |
| 快速脚本、日常开发 | requests |
| 需要异步/高性能 | aiohttp(第 63 章讲) |
requests 的代码可读性和开发效率远超 urllib。除非有严格的依赖限制,否则优先用 requests。
小结
urllib是标准库,功能完整但 API 偏底层。requests更人性化,自动处理编码、JSON、cookie 等细节。Session共享状态和连接,适合多请求场景。- 所有网络请求都要设
timeout,防止无限挂起。 - 用
raise_for_status()检查响应是否成功。
网络请求是程序跟外界通信的桥梁。写请求代码时,多考虑异常情况和超时处理,你的程序在弱网环境下会稳得多。
来源:参考了 runoob「Python3 urllib」和「Python requests」、liaoxuefeng「urllib」和「requests」等,改写后所得。