如何发送一个“多部分/forms的数据”在Python中的请求?
如何发送与Python中的请求的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
和httpbin.org让你知道你张贴了什么标题; 在response.json()
我们有:
>>> from pprint import pprint >>> pprint(response.json()['headers']) {u'Accept': u'*/*', u'Accept-Encoding': u'gzip, deflate, compress', u'Connection': u'close', u'Content-Length': u'141', u'Content-Type': u'multipart/form-data; boundary=33b4531a79be4b278de5f5688fab7701', u'Host': u'httpbin.org', u'User-Agent': u'python-requests/2.2.1 CPython/2.7.6 Darwin/13.2.0', u'X-Request-Id': u'eaf6baf8-fc3d-456b-b17d-e8219ccef1b1'}
files
也可以是一个二值元组的列表,如果你需要sorting和/或具有相同名称的多个字段:
requests.post('http://requestb.in/xucj9exu', files=(('foo', 'bar'), ('spam', 'eggs')))
如果您同时指定了files
和data
,那么它将取决于将用于创buildPOST正文的data
值 。 如果data
是一个string,只能使用它; 否则使用data
和files
,首先列出data
的元素。
由于以前的答案是写的,请求已经改变。 查看Github上的bug线程以获得更多的细节,以及这个例子的评论 。
简而言之,files参数需要一个dict
其中的键是表单字段的名称,值可以是string,也可以是2,3或4长度的元组,如POST部分中的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)
如果该值只是一个string,则文件名将与密钥相同,如下所示:
>>> 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
即使您不需要上传任何文件,也需要使用files
参数来发送多部分表单POST请求。
来自原始请求源:
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.
包含上传和表单字段的最简单的多部分表单请求将如下所示:
multipart_form_data = { 'file1': open('myfile.zip', 'rb'), 'file2': ('custom_file_name.zip', open('myfile.zip', 'rb')), 'action': ('', 'store'), 'path': ('', '/path1') } response = requests.post('https://httpbin.org/post', files=multipart_form_data) print(response.content)
☝ 请注意空string作为纯文本字段的元组中的第一个元素 – 这是文件名字段的占位符,仅用于文件上载,但是对于文本字段,必须存在空占位符才能使数据成为提交。
如果这个API对于你来说不够pyious,或者你需要使用相同的名称发布多个字段,那么考虑使用请求toolbelt ( pip install requests_toolbelt
),它是核心请求模块的扩展,它提供对file uploadstream的支持。以及可以用来代替files
的MultipartEncoder ,它接受既作为字典又作为元组的参数。
MultipartEncoder
既可以用于有或没有实际上传字段的多部分请求。 它必须分配给data
参数。
import requests from requests_toolbelt.multipart.encoder import MultipartEncoder multipart_data = MultipartEncoder( fields={ # a file upload field 'file': ('file.py', open('file.py', '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', 'store'), ('path', '/path1'), ('path', '/path2'), ('path', '/path3'), ) )