如何在python中发送多部分/表单数据请求?怎么发文件,我懂,但是怎么用这种方法发表单数据就不懂了。
当前回答
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 http.client
import mimetypes
from codecs import encode
conn = http.client.HTTPSConnection("data.XXXX.com")
dataList = []
boundary = 'wL36Yn8afVp8Ag7AmP8qZ0SA4n1v9T'
dataList.append(encode('--' + boundary))
dataList.append(encode('Content-Disposition: form-data; name=batchSize;'))
dataList.append(encode('Content-Type: {}'.format('text/plain')))
dataList.append(encode(''))
dataList.append(encode("1"))
dataList.append(encode('--' + boundary))
dataList.append(encode('Content-Disposition: form-data; name=file; filename={0}'.format('FileName-1.json')))
fileType = mimetypes.guess_type('FileName-1.json')[0] or 'application/octet-stream'
dataList.append(encode('Content-Type: {}'.format(fileType)))
dataList.append(encode(''))
with open('FileName-1.json', 'rb') as f:
dataList.append(f.read())
dataList.append(encode('--'+boundary+'--'))
dataList.append(encode(''))
body = b'\r\n'.join(dataList)
payload = body
headers = {
'Cookie': 'XXXXXXXXXXX',
'Content-type': 'multipart/form-data; boundary={}'.format(boundary)
}
conn.request("POST", "/fileupload/uri/XXXX", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
基本上,如果你指定了一个files参数(一个字典),那么请求将发送一个多部分的/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
httpbin.org让你知道你发布了什么头;在response.json()中我们有:
>>> 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'}
更好的是,通过使用元组而不是单个字符串或字节对象,您可以进一步控制每个部分的文件名、内容类型和额外的标题。元组应该包含2到4个元素;文件名、内容、可选的内容类型和可选的其他标头字典。
我将使用以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--
文件也可以是双值元组的列表,如果你需要排序和/或多个相同名称的字段:
requests.post(
'http://requestb.in/xucj9exu',
files=(
('foo', (None, 'bar')),
('foo', (None, 'baz')),
('spam', (None, 'eggs')),
)
)
如果同时指定了文件和数据,那么将使用什么来创建POST体取决于数据的值。如果data是字符串,则只使用它;否则,将同时使用数据和文件,首先列出数据中的元素。
还有一个优秀的请求-工具带项目,它包括高级的多部件支持。它接受与files形参相同格式的字段定义,但与请求不同,它默认不设置filename形参。此外,它可以从打开的文件对象中传输请求,其中请求将首先在内存中构造请求体:
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}
)
字段遵循相同的约定;使用2到4个元素的元组来添加文件名、mime类型的部分或额外的头文件。与files形参不同,如果不使用元组,则不会尝试查找默认的文件名值。
自从编写了以前的一些答案之后,请求已经发生了变化。在Github上看看这个问题的更多细节,这条评论是一个例子。
简而言之,files参数接受一个字典,键为表单字段的名称,值为字符串或2、3或4长度的元组,如请求快速入门中的POST一个多部分编码文件部分所述:
>>> 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,则filename属性将不包括在内:
>>> files = {'obvius_session_id': (None, '72c2b6f406cdabd578c5fd7598557c52')}
Content-Disposition: form-data; name="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
下面是使用请求上传带有附加参数的单个文件的简单代码片段:
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参数发送多部分表单POST请求。
文件= {}
不幸的是,这行不通。
您将需要放入一些虚拟值,例如。
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=