Come inviare un multipart/form-data
con richieste in python? Come inviare un file, ho capito, ma come inviare i dati del modulo con questo metodo non può capire.Come inviare un "multipart/form-data" con richieste in python?
risposta
In sostanza, se si specifica un parametro files
(un dizionario), quindi requests
invierà un POST multipart/form-data
invece di un POST application/x-www-form-urlencoded
. Non si sono limitati a utilizzare file effettivi in quel dizionario, però:
>>> import requests
>>> response = requests.post('http://httpbin.org/post', files=dict(foo='bar'))
>>> response.status_code
200
e httpbin.org ti permette di sapere che cosa gli header che hai postato con; in response.json()
abbiamo:
>>> 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
può essere anche una lista di tuple a due valori, se avete bisogno di ordinare e/o campi multipli con lo stesso nome:
requests.post('http://requestb.in/xucj9exu', files=(('foo', 'bar'), ('spam', 'eggs')))
Se si specifica sia files
e data
, quindi dipende dal valore di data
che verrà utilizzato per creare il corpo POST. Se data
è una stringa, verrà utilizzata solo; altrimenti vengono utilizzati sia data
e files
, con gli elementi in data
elencati per primi.
Codificherà qualsiasi cosa inviata a 'file' come parametro di un file reale nella codifica multipart. Questo non creerà un modulo rigoroso ma piuttosto un modulo con tutti i parametri del file. Vedi [questo] (https://github.com/kennethreitz/requests/issues/1081) come riferimento. –
@ sigmavirus24: l'API delle richieste si è evoluta da quando l'ho pubblicata; fammi indagare se questo ha bisogno di un aggiornamento ora. In ogni caso, questo angolo dell'API [ha avuto bisogno di una revisione per un po 'ora] (https://github.com/kennethreitz/requests/issues/935). –
scuse. StackOverflow lo mette nelle prime posizioni e dimentico che riorganizzare le domande e devo dare un'occhiata alle date delle risposte/delle domande. –
Poiché le risposte precedenti sono state scritte, le richieste sono cambiate. Dai un'occhiata allo bug thread at Github per maggiori dettagli e allo this comment per un esempio.
In breve, il parametro file prende uno dict
con la chiave come nome del campo modulo e il valore è una stringa o una tupla di 2, 3 o 4 lunghezze, come descritto nella sezione POST a Multipart-Encoded File nelle richieste quickstart:
>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
in quanto precede, la tupla è composto come segue:
(filename, data, content_type, headers)
Se il valore è solo una stringa, il nome del file sarà la stessa come la chiave, come il seguente:
>>> files = {'obvius_session_id': '72c2b6f406cdabd578c5fd7598557c52'}
Content-Disposition: form-data; name="obvius_session_id"; filename="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
Se il valore è una tupla e la prima voce è None
la proprietà nome del file non sarà incluso:
>>> files = {'obvius_session_id': (None, '72c2b6f406cdabd578c5fd7598557c52')}
Content-Disposition: form-data; name="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
Cosa fare se è necessario distinguere il 'nome' e' nomefile', ma hanno anche più campi con lo stesso nome? – Michael
Ho un problema simile a quello di @Michael. Puoi dare un'occhiata alla domanda e suggerire qualcosa? [collegamento] (http://stackoverflow.com/questions/30683352/how-to-upload-multipart-encode-file-and-form-data-as-a-payload) – Shaardool
qualcuno ha risolto questo problema avendo più campi con lo stesso nome? – user3131037
è necessario utilizzare il parametro files
per inviare una richiesta di modulo POST multipart anche quando si non è necessario caricare alcun file.
Dall'originale requests fonte:
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.
Il più semplice modulo di richiesta multipart che include sia i file da caricare e campi del modulo sarà simile a questo:
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)
☝ nota la stringa vuota come il primo elemento nella tupla per i campi di testo semplice - questo è un segnaposto per il campo filename che viene utilizzato solo per i caricamenti di file, ma per il campo di testo il segnaposto vuoto deve essere presente nell'ordine per i dati da inviare.
Se questa API non è sufficiente divinatorio per voi, o se avete bisogno di inviare più campi con lo stesso nome, quindi considerare l'utilizzo di requests toolbelt (
pip install requests_toolbelt
) che è un'estensione del modulo
core requests che fornisce il supporto per il file upload streaming oltre allo
MultipartEncoder che può essere usato al posto di
files
e che accetta parametri sia come dizionari che tuple.
MultipartEncoder
può essere utilizzato sia per richieste multipart con o senza campi di caricamento effettivi. Deve essere assegnato al parametro 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})
Se avete bisogno di inviare più campi con lo stesso nome, o se l'ordine dei campi modulo è importante, quindi una tupla o una lista può essere utilizzato al posto di un dizionario, vale a dire:
multipart_data = MultipartEncoder(
fields=(
('action', 'store'),
('path', '/path1'),
('path', '/path2'),
('path', '/path3'),
)
)
Grazie per questo. L'ordine delle chiavi era importante per me e questo ha aiutato molto. – Splendor
Incredibile. Inspiegabilmente, una API con cui sto lavorando richiede 2 valori diversi per la stessa chiave. È incredibile Grazie. – ajon
@ccpizza, cosa significa in realtà questa linea? > "('file.py', aperto ('file.py', 'rb'), 'text/plain')". Non funziona per me :( –
la tua domanda non è chiara. Cosa vuoi ottenere? Desideri inviare "multipart/form-data" senza un file upload nel modulo? –
Il fatto che il parametro 'files' sia usato per fare entrambe le cose è un'API pessima. Ho sollevato il problema intitolato [Invio di dati multipart - abbiamo bisogno di API migliori] (https://github.com/kennethreitz/requests/issues/935) per risolvere questo problema. Se accetti che l'uso del parametro 'files' per inviare dati mulitpart è fuorviante al massimo ti preghiamo di chiedere di cambiare l'API nel problema precedente. –
@PiotrDobrogost il problema è stato chiuso. Non incoraggiare le persone a commentare questioni chiuse, pertinenti o meno. –