杰瑞科技汇

python formdata请求

FormData 是一种用于构造表单数据的格式,通常用于在 HTML 表单中通过 POST 方法提交数据,特别是包含文件上传的场景,在 Python 中,我们通常不直接操作字符串来构建 FormData,而是使用专门的库来帮助我们轻松创建和发送它。

python formdata请求-图1
(图片来源网络,侵删)

核心概念

  1. multipart/form-data: 这是 FormData 在 HTTP 协议中使用的 Content-Type,它是一种多部分、二进制的数据格式,可以同时发送文本数据和文件数据。
  2. requests: 这是 Python 中最流行、最简单的 HTTP 请求库,它提供了 requests.post() 方法,并可以方便地处理 multipart/form-data
  3. files 参数: 在 requests.post() 中,files 参数就是用来发送文件和表单数据的关键。

使用 requests 库(最常用)

这是最直接、最推荐的方法。requests 库封装了所有复杂的细节。

安装 requests

如果你还没有安装,请先安装它:

pip install requests

发送纯文本表单数据

如果你想发送普通的键值对(如用户名、密码等),可以直接使用 data 参数。requests 会自动将其编码为 application/x-www-form-urlencoded 格式,对于 FormData,我们需要使用 files 参数。

import requests
# 目标 URL
url = 'https://httpbin.org/post' # httpbin.org 是一个测试 HTTP 请求的网站
# 表单数据 (键值对)
form_data = {
    'username': 'test_user',
    'password': '123456',
    'description': 'This is a test description.'
}
# 发送 POST 请求
# 使用 data 参数会自动编码为 application/x-www-form-urlencoded
# 对于 FormData,我们需要使用 files 参数,即使没有文件
response = requests.post(url, data=form_data)
# 打印响应
print("Status Code:", response.status_code)
print("Response Text:")
print(response.text)

发送包含文件的表单数据(核心用法)

这是 FormData 最常见的用途,在 files 参数中,你需要指定一个字典,其中键是表单字段名,值是一个元组 (文件名, 文件对象, content_type)

python formdata请求-图2
(图片来源网络,侵删)
import requests
url = 'https://httpbin.org/post'
# 准备要上传的文件
# 假设你有一个名为 'my_image.png' 的文件在当前目录
try:
    with open('my_image.png', 'rb') as f:
        files = {
            # 'file_field_name': (file_name, file_object, content_type)
            'profile_pic': ('my_image.png', f, 'image/png')
        }
        # 表单数据
        data = {
            'username': 'file_uploader',
            'caption': 'My beautiful photo'
        }
        # 发送请求
        # files 和 data 可以同时使用
        response = requests.post(url, files=files, data=data)
        print("Status Code:", response.status_code)
        print("Response JSON:")
        # httpbin.org 会返回你发送的所有数据,方便你检查
        print(response.json())
except FileNotFoundError:
    print("错误:请确保 'my_image.png' 文件存在于当前目录。")

files 参数详解:

files 参数的值是一个字典,字典的每个键对应表单中的一个字段名,值通常是一个元组,格式为:

(filename, file_object, content_type)

  • filename (字符串): 你希望在服务器上看到的文件名。
  • file_object: 一个文件类的对象,必须以二进制模式 ('rb') 打开。
  • content_type (字符串): 文件的 MIME 类型,'image/png', 'text/plain', 'application/pdf',这个值会自动设置请求头 Content-Type 中的 boundarytype

简写形式: 如果你不关心文件名和 content_type,可以只提供文件对象:

files = {'some_file': open('report.pdf', 'rb')}

requests 会尝试自动推断文件名和类型,但最好明确指定,以确保兼容性。


手动构建 multipart/form-data(不推荐,仅用于理解)

虽然 requests 能自动处理,但了解其背后的原理也很有帮助。multipart/form-data 格式由多个部分组成,每个部分之间用 boundary(一个随机字符串)分隔。

一个简单的 FormData 示例:

POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="username"
John Doe
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="example.txt"
Content-Type: text/plain
This is the content of the file.
------WebKitFormBoundary7MA4YWxkTrZu0gW--

手动构建这个字符串非常繁琐且容易出错,你需要:

  1. 生成一个唯一的 boundary
  2. 为每个部分构建头部(Content-Disposition, Content-Type)。
  3. 添加数据内容。
  4. boundary 正确地分隔所有部分。
  5. 在末尾添加 --boundary-- 表示结束。

强烈建议你始终使用 requests 或其他高级库来处理,而不是手动拼接字符串。


完整示例:同时上传文件和文本数据

这个例子综合了前面的知识点,模拟一个真实的用户头像上传场景。

import requests
# 目标 API 端点 (使用 httpbin.org 进行演示)
url = 'https://httpbin.org/post'
# 1. 准备要上传的文件
try:
    with open('my_image.png', 'rb') as f_image:
        # 2. 准备文本表单数据
        #    使用 data 参数来发送非文件字段
        form_data = {
            'user_id': 'user123',
            'action': 'update_avatar'
        }
        # 3. 准备文件数据
        #    使用 files 参数来发送文件
        #    'avatar' 是服务器期望的字段名
        files = {
            'avatar': ('my_image.png', f_image, 'image/png')
        }
        # 4. 发送 POST 请求
        #    requests 会自动设置正确的 Content-Type (multipart/form-data)
        #    和 boundary
        print("正在发送请求...")
        response = requests.post(url, data=form_data, files=files)
        # 5. 处理响应
        if response.status_code == 200:
            print("\n请求成功!")
            # httpbin.org 返回的 JSON 中,'form' 包含文本数据,'files' 包含文件数据
            response_json = response.json()
            print("\n服务器收到的表单数据:")
            print(response_json.get('form'))
            print("\n服务器收到的文件数据:")
            print(response_json.get('files'))
        else:
            print(f"\n请求失败,状态码: {response.status_code}")
            print(response.text)
except FileNotFoundError:
    print("错误:请确保 'my_image.png' 文件存在于当前目录。")
except Exception as e:
    print(f"发生错误: {e}")

总结与关键点

任务 推荐方法 示例代码
发送纯文本表单 使用 requests.post()data 参数 requests.post(url, data={'key': 'value'})
发送文件 使用 requests.post()files 参数 requests.post(url, files={'file': ('name', f_obj, 'type')})
同时发送文件和文本 datafiles 参数一起使用 requests.post(url, data=text_data, files=files_data)
获取文件对象 使用 with open('file.png', 'rb') as f: 确保文件以二进制读模式打开
Content-Type requests 自动设置 无需手动设置,它会变成 multipart/form-data; boundary=...

对于任何涉及 FormData 的请求,requests 库都是你的首选工具,它简单、强大且能避免手动处理复杂格式的痛苦。

分享:
扫描分享到社交APP
上一篇
下一篇