Requests - 文件上传
Requests: 轻松的文件上传
Section titled “Requests: 轻松的文件上传”requests 库使通过 HTTP POST 请求上传文件变得非常简单。这对于与需要提交文件的 Web 应用程序交互至关重要,例如上传图片、文档或数据文件。本章将介绍如何上传单个和多个文件,以及如何自定义文件上传。
我们将使用 https://httpbin.org/post 作为测试端点,它会回显 POST 请求的详细信息,包括上传的文件。
上传单个文件
Section titled “上传单个文件”要上传文件,你可以将一个字典传递给 requests.post() 的 files 参数。字典的键是服务器预期的字段名,值是类似文件的对象。
上传文件时,在二进制模式 ('rb') 下打开文件至关重要。使用 with 语句(上下文管理器)可以确保请求完成后文件自动关闭,这是一种最佳实践。
示例:上传 test.txt
Section titled “示例:上传 test.txt”首先,在你的项目目录中创建一个名为 test.txt 的示例文件,并添加一些内容:
test.txt 的内容:
Section titled “test.txt 的内容:”This is a test file for demonstrating file uploads with Python Requests.现在,让我们编写 Python 代码来上传它:
import requests
url = 'https://httpbin.org/post'file_path = 'test.txt'
# 最佳实践:使用上下文管理器来处理文件try: with open(file_path, 'rb') as f: files_to_upload = {'file': f} # 'file' 是字段名 response = requests.post(url, files=files_to_upload)
print(f"Status Code: {response.status_code}") # httpbin.org/post 返回一个包含上传详情的 JSON 响应 response_data = response.json() print("上传的文件内容(来自服务器响应):") print(response_data['files']['file'])
except FileNotFoundError: print(f"错误:文件 {file_path} 未找到。")except requests.exceptions.RequestException as e: print(f"发生错误:{e}")输出(示例)
Section titled “输出(示例)”Status Code: 200Uploaded file content (from server response):This is a test file for demonstrating file uploads with Python Requests.在来自 httpbin.org 的响应中,files 字段将包含上传文件的内容,从而确认上传成功。
自定义文件上传
Section titled “自定义文件上传”你可以通过提供一个元组(而不是仅仅是文件对象)来为上传的文件自定义文件名、内容类型和添加自定义头部信息 (custom headers)。
示例:指定文件名、内容类型和自定义头部信息
Section titled “示例:指定文件名、内容类型和自定义头部信息”import requests
url = 'https://httpbin.org/post'file_path = 'test.txt' # 假设 test.txt 存在
# 元组格式:(文件名, 文件对象, 内容类型, 自定义头部)# 内容类型和自定义头部是可选的。
try: with open(file_path, 'rb') as f: files_spec = { 'document': ('report.txt', f, 'text/plain', {'X-Custom-Info': 'MyReportV1'}) } response = requests.post(url, files=files_spec)
print(f"Status Code: {response.status_code}") response_data = response.json() print("服务器响应(files 部分):") print(response_data['files']) print("服务器响应(headers 部分 - 查看 Content-Disposition):") # 实际的多部分头部很复杂,httpbin 显示的是解析后的文件部分。 # 要查看 requests 发送的 Content-Disposition 头部,你需要检查原始请求或使用 Wireshark 等工具。 # httpbin 在键 'document' 下显示文件内容。
except FileNotFoundError: print(f"错误:文件 {file_path} 未找到。")except requests.exceptions.RequestException as e: print(f"发生错误:{e}")输出(示例,重点关注响应中的 ‘files’ 部分)
Section titled “输出(示例,重点关注响应中的 ‘files’ 部分)”Status Code: 200Server Response (files part):{'document': 'This is a test file for demonstrating file uploads with Python Requests.'}Server Response (headers part - to see Content-Disposition):...在这种情况下,服务器将看到使用字段名 document、文件名 report.txt、内容类型 text/plain 以及与此多部分 (multipart) 请求部分关联的自定义头部 X-Custom-Info 上传的文件。
上传多个文件
Section titled “上传多个文件”要在单个请求中上传多个文件,只需向 files 字典添加更多条目即可。每个键值对代表一个要上传的文件。
示例:上传两个文件
Section titled “示例:上传两个文件”假设你有一个 file1.txt 和一个 image.png。
import requests
url = 'https://httpbin.org/post'
# 如果文件不存在,为示例创建虚拟文件with open('file1.txt', 'w') as f1: f1.write('Content of file1')with open('image.png', 'wb') as f2: f2.write(b'\x89PNG\r\n\x1a\n\0\0\0\rIHDR...') # 虚拟 PNG 数据
files_to_upload = []try: # 准备文件列表以便使用上下文管理器打开 # (表单中的文件名, 磁盘上的实际文件名, 如果需要的内容类型) file_specs = [ ('text_file', 'file1.txt', 'text/plain'), ('image_file', 'image.png', 'image/png') ]
# 构建用于 requests 的 files 字典 # 需要保持文件对象打开直到请求发送 opened_files = [] # 用于存放需要关闭的文件对象(如果不为每个文件使用 with 语句) files_dict_for_requests = {}
for form_name, disk_filename, content_type in file_specs: f_obj = open(disk_filename, 'rb') opened_files.append(f_obj) files_dict_for_requests[form_name] = (disk_filename, f_obj, content_type)
response = requests.post(url, files=files_dict_for_requests)
print(f"Status Code: {response.status_code}") response_data = response.json() print("上传的文件(来自服务器响应):") print(response_data['files'])
finally: for f_obj in opened_files: f_obj.close()输出(示例,重点关注 ‘files’ 部分)
Section titled “输出(示例,重点关注 ‘files’ 部分)”Status Code: 200Uploaded files (from server response):{ "image_file": "data:image/png;base64,...", "text_file": "Content of file1"}注意:httpbin.org 可能会将二进制文件内容作为 base64 编码的 数据 URI (data URI) 返回。重要的是响应的 files 部分中同时存在 image_file 和 text_file 键,这表明它们已被服务器接收。
将内存中的内容作为文件发送
Section titled “将内存中的内容作为文件发送”你不必总是从磁盘文件读取内容。你也可以直接发送字符串或字节内容,就像它们是文件一样:
import requests
url = 'https://httpbin.org/post'
files = {'file': ('custom_filename.txt', 'Hello, this is in-memory content!')}response = requests.post(url, files=files)
print(f"Status Code: {response.status_code}")response_data = response.json()print(response_data['files']['file'])输出(示例)
Section titled “输出(示例)”Status Code: 200Hello, this is in-memory content!实际应用场景
Section titled “实际应用场景”文件上传在 Web 应用程序中非常常见,用于实现以下功能:用户头像更新、提交报告或文档、向消息附加文件,或上传数据集进行处理等。
始终参考你正在交互的服务的 API 文档,以了解文件上传所需的字段名、文件类型和大小限制。