Wie sende ich einen multipart/form-data
mit Anfragen in Python? Wie man eine Datei sendet, verstehe ich, aber wie man die Formulardaten mit dieser Methode sendet, kann nicht verstehen.
Wenn Sie einen files
-Parameter (ein Wörterbuch) angeben, sendet requests
grundsätzlich einen multipart/form-data
POST anstelle eines application/x-www-form-urlencoded
-POST. Sie sind jedoch nicht darauf beschränkt, tatsächliche Dateien in diesem Wörterbuch zu verwenden:
>>> import requests
>>> response = requests.post('http://httpbin.org/post', files=dict(foo='bar'))
>>> response.status_code
200
und httpbin.org informiert Sie darüber, mit welchen Headern Sie gepostet haben. in response.json()
haben wir:
>>> 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'}
Besser noch, Sie können den Dateinamen, den Inhaltstyp und zusätzliche Kopfzeilen für jeden Teil weiter steuern, indem Sie anstelle eines einzelnen String- oder Byte-Objekts ein Tuple verwenden. Es wird erwartet, dass der Tupel zwischen 2 und 4 Elemente enthält. den Dateinamen, den Inhalt, optional einen Inhaltstyp und ein optionales Wörterbuch mit weiteren Kopfzeilen.
Ich würde das Tupel-Formular mit None
als Dateinamen verwenden, sodass der filename="..."
-Parameter aus der Anforderung für diese Teile gelöscht wird:
>>> 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--
files
kann auch eine Liste von zwei Werten sein, wenn Sie eine Bestellung und/oder mehrere Felder mit demselben Namen benötigen:
requests.post('http://requestb.in/xucj9exu', files=(('foo', (None, 'bar')), ('spam', (None, 'eggs'))))
Wenn Sie sowohl files
als auch data
angeben, hängt es vom value von data
ab, was zur Erstellung des POST - Body verwendet wird. Wenn data
eine Zeichenfolge ist, wird nur diese verwendet. Andernfalls werden sowohl data
als auch files
verwendet, wobei die Elemente in data
zuerst aufgeführt werden.
Es gibt auch das hervorragende requests-toolbelt
-Projekt, das fortgeschrittene Multipart-Unterstützung beinhaltet. Es sind Felddefinitionen im gleichen Format wie der Parameter files
erforderlich. Im Gegensatz zu requests
wird jedoch kein Dateiname-Parameter festgelegt. Außerdem kann die Anforderung von geöffneten Dateiobjekten gestreamt werden, wobei requests
den Anforderungshauptteil zuerst im Speicher erstellt.
Seit dem Schreiben der vorherigen Antworten haben sich die Anforderungen geändert. Schauen Sie sich den Thread bug unter Github an für weitere Details und diesen Kommentar für ein Beispiel.
Kurz gesagt, der files-Parameter benötigt eine dict
, wobei der Schlüssel der Name des Formularfelds ist und der Wert entweder eine Zeichenfolge oder ein 2, 3 oder 4-Tupel ist, wie in Abschnitt POST a beschrieben Multipart-kodierte Datei im Schnellstart der Anforderung:
>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-Excel', {'Expires': '0'})}
Der Tupel setzt sich wie folgt zusammen:
(filename, data, content_type, headers)
Wenn der Wert nur eine Zeichenfolge ist, stimmt der Dateiname mit dem Schlüssel überein.
>>> files = {'obvius_session_id': '72c2b6f406cdabd578c5fd7598557c52'}
Content-Disposition: form-data; name="obvius_session_id"; filename="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
Wenn der Wert ein Tuple ist und der erste Eintrag None
ist, wird die Eigenschaft "Dateiname" nicht eingeschlossen:
>>> files = {'obvius_session_id': (None, '72c2b6f406cdabd578c5fd7598557c52')}
Content-Disposition: form-data; name="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
Sie müssen den Parameter files
verwenden, um ein multipart-Formular POST - Anforderung gerade zu senden, wenn Sie keine Dateien hochladen müssen.
Von den ursprünglichen Anfragen Quelle:
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.
Der relevante Teil ist: file-Tuple can be a
2-Tuple
, 3-Tuple
or a
4-Tuple
.
Basierend auf den obigen Angaben sieht die einfachste mehrteilige Formularanforderung, die sowohl hochzuladende Dateien als auch Formularfelder enthält, folgendermaßen aus:
multipart_form_data = {
'file2': ('custom_file_name.Zip', open('myfile.Zip', 'rb')),
'action': (None, 'store'),
'path': (None, '/path1')
}
response = requests.post('https://httpbin.org/post', files=multipart_form_data)
print(response.content)
{Beachten Sie die None
als erstes Argument im Tuple für Klartextfelder. Dies ist ein Platzhalter für das Dateinamensfeld, das nur für das Hochladen von Dateien verwendet wird. Für Textfelder muss jedoch None
als erster Parameter übergeben werden die zu übermittelnden Daten.
pip install requests_toolbelt
) in Erwägung ziehen. Dies ist eine Erweiterung der core-Anfragen . Dieses Modul bietet Unterstützung für das Hochladen von Dateien sowie den MultipartEncoder , der anstelle von files
verwendet werden kann, und der Parameter sowohl als Wörterbücher als auch als Tupel akzeptiert.MultipartEncoder
kann sowohl für mehrteilige Anforderungen mit als auch ohne tatsächliche Upload-Felder verwendet werden. Es muss dem Parameter data
zugewiesen werden.
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
multipart_data = MultipartEncoder(
fields={
# a file upload field
'file': ('file.Zip', open('file.Zip', '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})
Wenn Sie mehrere Felder mit demselben Namen senden müssen oder die Reihenfolge der Formularfelder wichtig ist, kann anstelle eines Wörterbuchs ein Tupel oder eine Liste verwendet werden, d. H .:
multipart_data = MultipartEncoder(
fields=(
('action', 'ingest'),
('item', 'spam'),
('item', 'sausage'),
('item', 'eggs'),
)
)
Sie müssen das name
-Attribut der Upload-Datei verwenden, die sich im HTML-Code der Site befindet. Beispiel:
autocomplete="off" name="image">
Sie sehen name="image">
? Sie finden es im HTML-Code einer Website zum Hochladen der Datei. Sie müssen es verwenden, um die Datei mit Multipart/form-data
hochzuladen.
skript:
import requests
site = 'https://prnt.sc/upload.php' # the site where you upload the file
filename = 'image.jpg' # name example
Fügen Sie hier anstelle von image den Namen der Upload-Datei in HTML hinzu
up = {'image':(filename, open(filename, 'rb'), "multipart/form-data")}
Wenn für das Hochladen ein Klick auf die Schaltfläche zum Hochladen erforderlich ist, können Sie Folgendes verwenden:
data = {
"Button" : "Submit",
}
Starten Sie dann die Anfrage
request = requests.post(site, files=up, data=data)
Und fertig, die Datei wurde erfolgreich hochgeladen
Hier ist das Python-Snippet, das Sie benötigen, um eine große einzelne Datei als mehrteilige Formulardaten hochzuladen. Mit NodeJs Multer-Middleware auf der Serverseite.
import requests
latest_file = 'path/to/file'
url = "http://httpbin.org/apiToUpload"
files = {'fieldName': open(latest_file, 'rb')}
r = requests.put(url, files=files)
Für die Serverseite lesen Sie bitte die Dokumentation des Mulder unter: https://github.com/expressjs/multer Hier wird das Feld single ('fieldName') verwendet, um eine einzige Datei zu akzeptieren, wie in
var upload = multer().single('fieldName');
Hier ist das einfache Code-Snippet zum Hochladen einer einzelnen Datei mit zusätzlichen Parametern mithilfe von Anforderungen:
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)
Bitte beachten Sie, dass Sie keinen Inhaltstyp explizit angeben müssen.
HINWEIS: Wollte zu einer der obigen Antworten einen Kommentar abgeben, konnte aber wegen mangelnder Reputation hier keine neue Antwort verfassen.