requests
库发送multipart/form-data
格式的数据?我知道如何发送文件,但不知道如何用这种方法发送表单数据。请帮我解答。requests
库发送multipart/form-data
格式的数据?我知道如何发送文件,但不知道如何用这种方法发送表单数据。请帮我解答。files
参数(一个字典),那么requests
将发送一个multipart/form-data
的POST请求,而不是application/x-www-form-urlencoded
的POST请求。在该字典中,你并不局限于使用实际的文件。>>> import requests
>>> response = requests.post('http://httpbin.org/post', files=dict(foo='bar'))
>>> response.status_code
200
>>> from pprint import pprint
>>> pprint(response.json()['headers'])
{'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'close',
'Content-Length': '141',
'Content-Type': 'multipart/form-data; '
'boundary=c7cbfdd911b4e720f1dd8f479c50bc7f',
'Host': 'httpbin.org',
'User-Agent': 'python-requests/2.21.0'}
files
参数时,不应设置Content-Type
头,将此留给requests
处理,因为它需要在头部中指定与请求体中使用的值匹配的(唯一的)边界值。None
,这样请求中的filename="..."
参数就会被忽略。>>> files = {'foo': 'bar'}
>>> print(requests.Request('POST', 'http://httpbin.org/post', files=files).prepare().body.decode('utf8'))
--bb3f05a247b43eede27a124ef8b968c5
Content-Disposition: form-data; name="foo"; filename="foo"
bar
--bb3f05a247b43eede27a124ef8b968c5--
>>> files = {'foo': (None, 'bar')}
>>> print(requests.Request('POST', 'http://httpbin.org/post', files=files).prepare().body.decode('utf8'))
--d5ca8c90a869c5ae31f70fa3ddb23c76
Content-Disposition: form-data; name="foo"
bar
--d5ca8c90a869c5ae31f70fa3ddb23c76--
files
也可以是一个包含两个值的元组列表,如果你需要排序和/或具有相同名称的多个字段:
requests.post(
'http://requestb.in/xucj9exu',
files=(
('foo', (None, 'bar')),
('foo', (None, 'baz')),
('spam', (None, 'eggs')),
)
)
files
和data
,那么取决于data
的值将用于创建POST请求的主体。如果data
是一个字符串,则只使用它;否则,同时使用data
和files
,其中data
中的元素先列出。requests-toolbelt
项目,其中包括高级多部分支持。它采用与files
参数相同格式的字段定义,但与requests
不同,默认情况下不设置文件名参数。此外,它可以从打开的文件对象流式传输请求,而requests
会首先在内存中构建请求主体。from requests_toolbelt.multipart.encoder import MultipartEncoder
mp_encoder = MultipartEncoder(
fields={
'foo': 'bar',
# plain file object, no filename or mime type produces a
# Content-Disposition header with just the part name
'spam': ('spam.txt', open('spam.txt', 'rb'), 'text/plain'),
}
)
r = requests.post(
'http://httpbin.org/post',
data=mp_encoder, # The MultipartEncoder is posted as data, don't use files=...!
# The MultipartEncoder provides the content-type header with the boundary:
headers={'Content-Type': mp_encoder.content_type}
)
files
参数不同,如果您不使用元组,则不会尝试找到默认的filename
值。multipart/form-data
的 Content-Type 必须 包括用于划分 post 请求主体中各部分的边界值。不设置 Content-Type
标头会导致 requests
自动设置正确的值。 - Martijn Pieters自某些之前的回答以来,Requests 已经有所改变。请查看Github 上的此问题以获取更多详细信息,并查看此评论以获得示例。
简而言之,files
参数接受一个字典,其中键是表单字段的名称,而值可以是字符串或2、3或4个长度的元组,如在 Requests 快速入门指南中的POST a Multipart-Encoded File部分所述:
>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
上述中,元组的组成如下:
(filename, data, content_type, headers)
如果值只是一个字符串,则文件名将与键相同,如下所示:
>>> files = {'obvius_session_id': '72c2b6f406cdabd578c5fd7598557c52'}
Content-Disposition: form-data; name="obvius_session_id"; filename="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
如果值是元组且第一项为None
,则不包括文件名属性:>>> files = {'obvius_session_id': (None, '72c2b6f406cdabd578c5fd7598557c52')}
Content-Disposition: form-data; name="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
files
元组的第一个值来传递非文件multipart/form-data
参数了。您需要改用requests.post
的data
参数来发送附加的非文件multipart/form-data
参数。 - Lucas CimonNone
而不是空字符串似乎有效。 - Alexandre Blin即使您不需要上传任何文件,也需要使用files
参数来发送多部分表单POST请求。
来自requests的原始代码:
def request(method, url, **kwargs):
"""Constructs and sends a :class:`Request <Request>`.
...
:param files: (optional) Dictionary of ``'name': file-like-objects``
(or ``{'name': file-tuple}``) for multipart encoding upload.
``file-tuple`` can be a 2-tuple ``('filename', fileobj)``,
3-tuple ``('filename', fileobj, 'content_type')``
or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``,
where ``'content-type'`` is a string
defining the content type of the given file
and ``custom_headers`` a dict-like object
containing additional headers to add for the file.
相关部分是:file-tuple
,它可以是:
2-tuple
(文件名,文件对象)3-tuple
(文件名,文件对象,内容类型)4-tuple
(文件名,文件对象,内容类型,自定义标头)。☝可能不明显的是,
fileobj
可以是实际文件对象(处理文件时),也可以是字符串(处理纯文本字段时)。
基于上述信息,包含要上传的文件和表单字段的最简单的多部分请求如下所示:
import requests
multipart_form_data = {
'upload': ('custom_file_name.zip', open('myfile.zip', 'rb')),
'action': (None, 'store'),
'path': (None, '/path1')
}
response = requests.post('https://httpbin.org/post', files=multipart_form_data)
print(response.content)
☝ 请注意纯文本字段元组中第一个参数为None
—— 这是用于文件上传的文件名字段的占位符,但对于文本字段,必须将None
作为第一个参数传递才能提交数据。
如果您需要发布具有相同名称的多个字段,则可以将载荷定义为元组(或列表)的列表,而不是字典:
multipart_form_data = (
('file2', ('custom_file_name.zip', open('myfile.zip', 'rb'))),
('action', (None, 'store')),
('path', (None, '/path1')),
('path', (None, '/path2')),
('path', (None, '/path3')),
)
如果上述API对你来说不够Pythonic,那么考虑使用requests toolbelt(pip install requests_toolbelt
),它是核心requests模块的扩展,提供了文件上传流和MultipartEncoder,可以替代files
,还可以让你将负载定义为字典、元组或列表。
MultipartEncoder
可用于带有或不带有实际上传字段的多部分请求。它必须分配给data
参数。
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
multipart_data = MultipartEncoder(
fields={
# a file upload field
'file': ('file.zip', open('file.zip', 'rb'), 'text/plain')
# plain text fields
'field0': 'value0',
'field1': 'value1',
}
)
response = requests.post('http://httpbin.org/post', data=multipart_data,
headers={'Content-Type': multipart_data.content_type})
如果您需要发送具有相同名称的多个字段,或者表单字段的顺序很重要,则可以使用元组或列表代替字典:
multipart_data = MultipartEncoder(
fields=(
('action', 'ingest'),
('item', 'spam'),
('item', 'sausage'),
('item', 'eggs'),
)
)
None
代替空字符串。这样,请求将不会包括文件名。因此,代替Content-Disposition: form-data; name="action"; filename=""
,它将是Content-Disposition: form-data; name="action"
。对于服务器将这些字段视为表单字段而不是文件,这对我非常关键。 - Mitar这里是使用requests上传单个文件且带有额外参数的简单代码片段:
url = 'https://<file_upload_url>'
fp = '/Users/jainik/Desktop/data.csv'
files = {'file': open(fp, 'rb')}
payload = {'file_id': '1234'}
response = requests.put(url, files=files, data=payload, verify=False)
请注意,您不需要显式指定任何内容类型。
注:想要评论以上答案之一,但由于声望低无法评论,因此在此撰写了新的回复。files
和data
都作为字典。 - WestCoastProjectsPOST
请求中指定files
参数,请求的Content-Type
会自动设置为multipart/form-data
(后面跟随着用于在多部分负载中分隔每个主体部分的boundary
字符串),无论您只发送files
,还是同时发送form-data
和files
(因此,在这种情况下不应尝试手动设置Content-Type
)。而如果只发送form-data
,则Content-Type
将自动设置为application/x-www-form-urlencoded
。Content-Type
标头以验证上述内容,使用下面给出的示例,该示例显示如何上传多个文件(或单个文件),并且(可选)具有相同的key
(即,在下面的情况下为'files'
),以及可选的form-data
(即,在下面的示例中为data=data
)。关于如何POST
单个和多个files
的文档分别可以在这里和这里找到。如果您需要上传大型文件而无需将其读入内存,请查看流式上传。import requests
url = 'http://127.0.0.1:8000/submit'
files = [('files', open('a.txt', 'rb')), ('files', open('b.txt', 'rb'))]
#file = {'file': open('a.txt','rb')} # to send a single file
data ={"name": "foo", "point": 0.13, "is_accepted": False}
r = requests.post(url=url, data=data, files=files)
print(r.json())
print(r.request.headers['content-type'])
name
属性。例如:autocomplete="off" name="image">
name="image">
吗?你可以在上传文件的网站的HTML中找到它。你需要使用它来使用Multipart/form-data
上传文件。import requests
site = 'https://prnt.sc/upload.php' # the site where you upload the file
filename = 'image.jpg' # name example
up = {'image':(filename, open(filename, 'rb'), "multipart/form-data")}
data = {
"Button" : "Submit",
}
然后开始请求
request = requests.post(site, files=up, data=data)
完成了,文件已成功上传。
import requests
# assume sending two files
url = "put ur url here"
f1 = open("file 1 path", 'rb')
f2 = open("file 2 path", 'rb')
response = requests.post(url,files={"file1 name": f1, "file2 name":f2})
print(response)
import json
import os
import requests
from requests_toolbelt import MultipartEncoder
AUTH_API_ENDPOINT = "http://localhost:3095/api/auth/login"
def file_upload(path_img, token ):
url = 'http://localhost:3095/api/shopping/product/image'
name_img = os.path.basename(path_img)
mp_encoder = MultipartEncoder(
fields={
'email': 'mcm9@gmail.com',
'source': 'tmall',
'productId': 'product_0001',
'image': (name_img, open(path_img, 'rb'), 'multipart/form-data')
#'spam': ('spam.txt', open('spam.txt', 'rb'), 'text/plain'),
}
)
head = {'Authorization': 'Bearer {}'.format(token),
'Content-Type': mp_encoder.content_type}
with requests.Session() as s:
result = s.post(url, data=mp_encoder, headers=head)
return result
def do_auth(username, password, url=AUTH_API_ENDPOINT):
data = {
"email": username,
"password": password
}
# sending post request and saving response as response object
r = requests.post(url=url, data=data)
# extracting response text
response_text = r.text
d = json.loads(response_text)
# print(d)
return d
if __name__ == '__main__':
result = do_auth('mcm4@gmail.com','123456')
token = result.get('data').get('payload').get('token')
print(token)
result = file_upload('/home/mcm/Pictures/1234.png',token)
print(result.json())
files={"foo": "bar"}
当我尝试将文件上传到Bitbucket的REST API时,遇到了这个问题,不得不编写这个可怕的东西,以避免可怕的“不支持的媒体类型”错误:
url = "https://my-bitbucket.com/rest/api/latest/projects/FOO/repos/bar/browse/foobar.txt"
payload = {'branch': 'master',
'content': 'text that will appear in my file',
'message': 'uploading directly from python'}
files = {"foo": "bar"}
response = requests.put(url, data=payload, files=files)
:O=
requests.put(url, files=payload)
吗? - Nizam Mohamedcurl命令:
curl -X PUT http://127.0.0.1:8080/api/xxx ...
-H 'content-type: multipart/form-data; boundary=----xxx' \
-F taskStatus=1
Python requests - 更复杂的POST请求:
updateTaskUrl = "http://127.0.0.1:8080/api/xxx"
updateInfoDict = {
"taskStatus": 1,
}
resp = requests.put(updateTaskUrl, data=updateInfoDict)
curl命令:
curl -X POST http://127.0.0.1:8080/api/xxx ...
-H 'content-type: multipart/form-data; boundary=----xxx' \
-F file=@/Users/xxx.txt
Python Requests - 发送一个多部分编码的文件:
filePath = "/Users/xxx.txt"
fileFp = open(filePath, 'rb')
fileInfoDict = {
"file": fileFp,
}
resp = requests.post(uploadResultUrl, files=fileInfoDict)
这是全部内容。