下面我将从最基础的用法开始,逐步讲解更复杂的场景,并提供完整的代码示例。

核心概念
requests 上传文件主要通过 requests.post() 方法实现,关键在于 files 参数,这个参数需要一个字典,
- 键:通常是后端服务器期望接收的文件字段名(
<input name="...">中的name属性)。 - 值:一个文件元组,格式为
(文件名, 文件对象, 内容类型)。
# files 参数的基本结构
files = {
'file_field_name': ('file_name_on_server', file_object, 'content_type')
}
content_type 是可选的,requests 通常可以自动推断。
最基础的上传:上传本地文件
这是最常见的情况,即上传你电脑上的一个文件。
代码示例:上传一个图片文件

import requests
# 目标上传URL
url = 'https://httpbin.org/post' # 这是一个测试服务器,会返回你发送的所有信息
# 1. 准备要上传的本地文件路径
file_path = 'my_image.png'
# 2. 打开文件,以二进制模式('rb')读取
# 使用 with 语句可以确保文件被正确关闭
with open(file_path, 'rb') as f:
# 3. 构建 files 字典
# 'file' 是后端接收文件时使用的字段名
# 'my_image.png' 是上传到服务器后,文件在表单中显示的名称
# f 是文件对象
files = {'file': ('my_image.png', f)}
# 4. 发送 POST 请求
response = requests.post(url, files=files)
# 5. 检查响应状态码
response.raise_for_status() # 如果请求失败 (状态码非 200), 会抛出异常
# 6. 打印服务器返回的内容
print("上传成功!")
print("响应状态码:", response.status_code)
# httpbin.org 会返回 JSON 格式的响应,其中包含了文件信息
print("服务器返回的 JSON:")
print(response.json())
代码解析:
with open(...): 强烈推荐使用with语句来处理文件,因为它会在代码块执行完毕后自动关闭文件,即使发生错误也不例外。'rb': 以二进制模式读取文件,这对于图片、视频、PDF 等非文本文件至关重要,即使是文本文件,也建议使用二进制模式上传,以避免编码问题。files参数: 我们传递了一个字典。requests会看到这个参数,并自动将请求的Content-Type设置为multipart/form-data,这是上传文件的标准格式。
上传内存中的文件(BytesIO)
如果你不需要将文件保存到磁盘,而是直接在内存中处理(从网络下载、由其他库生成等),可以使用 io.BytesIO。
代码示例:
import requests
import io
url = 'https://httpbin.org/post'
# 1. 准备文件内容(这里是字符串,但可以是任何字节)
file_content_bytes = b"This is the content of my file in memory."
# 2. 创建一个 BytesIO 对象
file_object = io.BytesIO(file_content_bytes)
# 3. 构建 files 字典
# 这次我们让 requests 自动推断内容类型
files = {
'file': ('memory_file.txt', file_object)
}
# 4. 发送请求
response = requests.post(url, files=files)
# 5. 处理响应
response.raise_for_status()
print("内存文件上传成功!")
print("响应内容:", response.json()['form'])
上传多个文件
requests 也支持在一次请求中上传多个文件,你只需要在 files 字典中为每个文件提供一个键即可。

代码示例:同时上传两个文件
import requests
url = 'https://httpbin.org/post'
# 准备两个本地文件
file1_path = 'my_image.png'
file2_path = 'my_document.pdf'
# 构建包含多个文件的 files 字典
# 'file1' 和 'file2' 是后端用来区分不同文件的字段名
files = {
'file1': ('image.png', open(file1_path, 'rb')),
'file2': ('document.pdf', open(file2_path, 'rb'))
}
try:
# 发送请求
response = requests.post(url, files=files)
response.raise_for_status()
print("多文件上传成功!")
print("服务器返回的文件信息:", response.json()['files'])
finally:
# !!!重要!!!
# 手动关闭所有打开的文件
for f in files.values():
f[1].close()
注意:当你直接传递 open() 的结果时,requests 不会为你关闭文件,你必须手动关闭它们,如 finally 块所示,这也是为什么使用 with open() 更安全的原因。
携带其他数据(表单数据)一起上传
上传文件时还需要提交一些额外的文本信息,比如用户名、描述等,你可以同时使用 files 和 data 参数。
data 参数用于普通的表单字段,files 参数用于文件字段。
代码示例:
import requests
url = 'https://httpbin.org/post'
file_path = 'my_image.png'
# 准备文件
with open(file_path, 'rb') as f:
# files 用于文件
files = {'file': ('my_image.png', f)}
# data 用于其他表单数据(键值对)
# 这相当于 <input type="text" name="username">
# <input type="text" name="description">
data = {
'username': 'test_user',
'description': 'This is a test image upload.'
}
# 同时发送 files 和 data
response = requests.post(url, files=files, data=data)
response.raise_for_status()
print("带数据的文件上传成功!")
# 查看表单数据和文件信息
print("表单数据:", response.json()['form'])
print("文件信息:", response.json()['files'])
高级用法与进阶
显示上传进度
requests 本身不直接支持进度条,但你可以结合 tqdm 库来实现一个非常酷炫的进度条。
安装 tqdm:
pip install tqdm
代码示例:
import requests
from tqdm import tqdm
url = 'https://httpbin.org/post'
file_path = 'my_image.png' # 假设这是一个大文件
# 获取文件大小用于进度条
file_size = os.path.getsize(file_path)
# 1. 创建一个 tqdm 进度条对象
# total=文件大小, unit='B', unit_scale=True, unit_divisor=1024
# desc 是进度条前缀
with tqdm(
total=file_size,
unit='B',
unit_scale=True,
unit_divisor=1024,
desc=file_path
) as progress_bar:
# 2. 定义一个回调函数,在每次数据块被发送后更新进度条
def update_progress(chunk):
progress_bar.update(len(chunk))
# 3. 打开文件并设置 data 的回调
with open(file_path, 'rb') as f:
files = {'file': (file_path, f)}
# 使用 data 参数的 hooks 机制
response = requests.post(
url,
files=files,
data={'description': 'File with progress bar'},
hooks={'response': lambda r, *args, **kwargs: progress_bar.close()},
# 流式传输,设置 chunksize
stream=True
)
response.raise_for_status()
print("带进度条的上传完成!")
自定义请求头
上传文件时,你可能需要添加自定义的 Authorization 头来验证身份。
import requests
url = 'https://your-upload-api.com/upload'
file_path = 'my_image.png'
headers = {
'Authorization': 'Bearer YOUR_API_TOKEN'
}
with open(file_path, 'rb') as f:
files = {'file': f}
response = requests.post(url, files=files, headers=headers)
print(response.json())
| 场景 | files 参数示例 |
data 参数示例 |
|---|---|---|
| 上传单个文件 | {'file': ('name.txt', open('f.txt', 'rb'))} |
不需要 |
| 上传内存文件 | {'file': ('name.txt', io.BytesIO(b'data'))} |
不需要 |
| 上传多个文件 | {'f1': (...), 'f2': (...)} |
不需要 |
| 文件 + 表单数据 | {'file': (...)} |
{'key': 'value'} |
requests 的文件上传功能非常强大且灵活,几乎可以满足所有常见的文件上传需求,记住最核心的 files 参数,并始终使用 with open() 来安全地处理文件。
