Content disposition form data python

Как отправить «multipart/form-data» с запросами в python?

Как отправить multipart/form-data с запросами в питоне? Как отправить файл, я понимаю, но как отправить данные формы этим способом не могу понять.

13 ответов

В основном, если вы укажете files параметр (словарь), то requests отправит multipart/form-data ПОСТ вместо application/x-www-form-urlencoded СООБЩЕНИЕ. Однако вы не ограничены использованием реальных файлов в этом словаре:

>>> 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']) 

files также может быть списком двухзначных кортежей, если вам нужно упорядочить и / или несколько полей с одинаковым именем:

requests.post('http://requestb.in/xucj9exu', files=(('foo', 'bar'), ('spam', 'eggs'))) 

Если вы укажете оба files а также data , то это зависит от стоимости data что будет использоваться для создания тела POST. Если data является строкой, будет использоваться только она; в противном случае оба data а также files используются с элементами в data указан первым

Так как предыдущие ответы были написаны, запросы изменились. Посмотрите на ветку об ошибках на Github для более подробной информации и этот комментарий для примера.

Короче говоря, параметр файлов принимает dict с ключом, являющимся именем поля формы, и значением, являющимся либо строкой, либо кортежем длиной 2, 3 или 4, как описано в разделе POST для файла, состоящего из нескольких частей, в быстром запуске запросов:

>>> url = 'http://httpbin.org/post' >>> files = )> 

В приведенном выше, кортеж составлен следующим образом:

(filename, data, content_type, headers) 

Если значение является просто строкой, имя файла будет таким же, как и у ключа, как показано ниже:

>>> files = Content-Disposition: form-data; name="obvius_session_id"; filename="obvius_session_id" Content-Type: application/octet-stream 72c2b6f406cdabd578c5fd7598557c52 

Если значение является кортежем, а первая запись None свойство filename не будет включено:

>>> files = 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 `. . :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ````) 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 can be a 2-tuple , 3-tuple or a 4-tuple ,

Исходя из вышеизложенного, простейший многочастный запрос формы, который включает в себя как файлы для загрузки, так и поля формы, будет выглядеть следующим образом:

multipart_form_data = < '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) 

Обратите внимание на пустую строку в качестве первого аргумента в кортеже для текстовых полей — это заполнитель для поля имени файла, который используется только для загрузки файла, но для текстовых полей пустой заполнитель все еще требуется для того, чтобы данные были отправлены,

Если этот API не является достаточно питоническим для вас, или если вам нужно опубликовать несколько полей с одним и тем же именем, рассмотрите возможность использования toolbelt запросов ( pip install requests_toolbelt ), который является расширением модуля основных запросов, который обеспечивает поддержку потоковой передачи файлов, а также MultipartEncoder, который можно использовать вместо files и который принимает параметры как словари, так и кортежи.

MultipartEncoder может использоваться как для составных запросов с фактическими полями загрузки, так и без них. Он должен быть назначен data параметр.

import requests from requests_toolbelt.multipart.encoder import MultipartEncoder multipart_data = MultipartEncoder( fields= < # a file upload field 'file': ('file.py', open('file.zip', 'rb'), 'text/plain') # plain text fields 'field0': 'value0', 'field1': 'value1', >) response = requests.post('http://httpbin.org/post', data=multipart_data, headers=) 

Если вам нужно отправить несколько полей с одним и тем же именем или если важен порядок полей формы, тогда вместо словаря можно использовать кортеж или список, то есть:

multipart_data = MultipartEncoder( fields=( ('action', 'ingest'), ('item', 'spam'), ('item', 'sausage'), ('item', 'eggs'), ) ) 

Источник

Send a HTTP POST request with Python requests library

requests is an popular, simple yet powerful HTTP library for Python. It allows you to easily prepare and send complex HTTP requests in a few lines of code. Using requests library is a popular way to abstract away the complexity of managing query strings, arguments, form-encode POST data, and many other things when it comes to making HTTP requests.

In this article, we will show you a few ways to send a HTTP POST request in Python requests library, from the simple one to the more complex requests including multipart POST data.

Send a simple POST in Python requests

A POST request is typically sent via an HTML form and results in a change on the server. HTTP POST method is often used when submitting login or contact forms or uploading files and images to the server.

In order to send a simple HTTP POST request with some form-encoded data, use the post method with data argument.

post_data = response = requests.post('https://httpbin.org/post', data=post_data) print(response) # OUTPUT

In the code snippet above, post_data is a Python dictionary contains all the POST data that you want to send out.

Send POST request with complex HTML form-encoded data

If you want to emulate a request sent by a HTML form, which contains form-encoded data, you can pass the data argument just like the example above. The data argument can also take in a tuple-based payload or a dictionary-based one with multiple elements in the same key.

payload_tuples = [('key1', 'value1'), ('key1', 'value2')] r1 = requests.post('https://httpbin.org/post', data=payload_tuples) payload_dict = r2 = requests.post('https://httpbin.org/post', data=payload_dict) print(r1.text == r2.text) # OUTPUT True

In the example above, the two tuple-based and dictionary-based payload does the same thing, which is sending a form-encoded data that use the same key for multiple field.

Send POST request with JSON data as string

There are times that you may want to send a JSON as string to a server via a POST request. For example, a few API only accepts complex data to be able to simplify the request body. If you pass in a string instead of a dict , the JSON data will be posted directly to the URL. In this example, we manually encode the JSON data to string with Python json library.

import json url = 'https://api.example.com/endpoint' payload = response = requests.post(url, data=json.dumps(payload))

If you’re using a more recent version of requests (>2.4.2), you can pass a json argument directly instead of manually encoding the dict.

url = 'https://api.github.com/some/endpoint' payload = response = requests.post(url, json=payload)

Please note that the only difference between data and json argument is that the json will set the Content-Type in the header to application/json , while POST requests sent with data will have Content-Type: application/x-www-form-urlencoded header.

The json parameter would be ignored if either data or files is passed.

Send Multipart-Encoded POST request

A HTTP multipart request is a HTTP request that HTTP clients construct to send files and data over to a HTTP Server. It is commonly used by browsers and HTTP clients to upload files to the server. Those files can be photos, music, binary, text or a combination of them.

If you didn’t know how it would look like in raw form, here it is.

POST /test HTTP/1.1 Host: example User-Agent: Mozilla/5.0 Gecko/2009042316 Firefox/3.0.10 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: http://example/example.htm Content-Type: multipart/form-data; boundary=2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f Content-Length: 514 --2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f Content-Disposition: form-data; name="datafile1"; filename="a.gif" Content-Type: image/gif GIF87a. D..; --2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f Content-Disposition: form-data; name="datafile2"; filename="b.gif" Content-Type: image/gif GIF87a. D..; --2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f Content-Disposition: form-data; name="datafile3"; filename="c.gif" Content-Type: image/gif GIF87a. D..; --2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f--

As you can see, the multipart data is big, and contains many files inside as well as their filenames. In requests , multipart-encoded POST request can be easily made using files argument.

url = 'https://httpbin.org/post' files = r = requests.post(url, files=files) r.text # OUTPUT < . "files": < "datafile1": "" >, . >

Please note that we opened the file in binary mode. I is strongly recommended that you open files in binary mode because requests attempt to automatically provide the Content-Length header for you. This value should be set to the number of bytes in the file, not the number of text characters in the string version of it. Errors may occur if you open the file in text mode.

If you need to send filenames, content types and other file details as well, use a 3-element tuple as value in the files dict. The tuple order should be (filename, file_object, content_type, expiration) .

url = 'https://httpbin.org/post' file1_detail = ('a.gif', open('a.gif', 'rb'), 'image/gif', ) files = r = requests.post(url, files=files) r.text # OUTPUT < . "files": < "datafile1": "" >, . >

Send multiple files in a Multipart-Encoded POST request

You can send more than one file in a single POST with requests library as well. It’s a little different than when you send a single file. In this case, the files dictionary should be a list of 2-element tuples following (form_field_name, file_info) syntax, where file_info should be a 3-element tuple that contains file details.

url = 'https://httpbin.org/post' multiple_files = [ . ('images', ('1.png', open('1.png', 'rb'), 'image/png')), . ('images', ('2.png', open('2.png', 'rb'), 'image/png'))] r = requests.post(url, files=multiple_files) r.text # OUTPUT < . 'files': 'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a', . >

Files should be opened in binary mode, otherwise Content-Length header can be set to an incorrect value and causing errors.

Send Large Multipart-Encoded POST request

There are times that your files is relatively big, you may want to stream the request instead of reading all of its contents into memory.

By default, requests does not support this, but there is a separate package which does – requests-toolbelt .

This use case is pretty rare, but if you want to find out more about it, you should read the toolbelt’s documentation. There are a section dedicated to Uploading Data via HTTP POST request, which contains tutorials on Streaming large multipart data and monitoring that process.

Источник

Читайте также:  Javascript add element in object
Оцените статью