如何发送一个“多部分/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'))) 

如果您同时指定了filesdata ,那么它将取决于将用于创buildPOST正文的data 。 如果data是一个string,只能使用它; 否则使用datafiles ,首先列出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'), ) )