Jak wysłać multipart/form-data
z zapytaniami w pythonie? Jak wysłać plik, rozumiem, ale nie można zrozumieć, jak wysłać dane formularza za pomocą tej metody.Jak wysłać "wieloczęściowy/formularz danych" z zapytaniami w python?
Odpowiedz
Zasadniczo, jeśli podasz files
parametr (słownika), a następnie requests
wyśle multipart/form-data
POST zamiast application/x-www-form-urlencoded
POST. Nie ograniczasz się jednak do używania rzeczywistych plików w tym słowniku, jednak:
>>> import requests
>>> response = requests.post('http://httpbin.org/post', files=dict(foo='bar'))
>>> response.status_code
200
i httpbin.org pozwala Ci dowiedzieć się, jakie nagłówki zamieściłeś; w response.json()
mamy:
>>> 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
może być również lista krotek dwie wartości, jeśli potrzeba uporządkowania i/lub wiele pól o tej samej nazwie:
requests.post('http://requestb.in/xucj9exu', files=(('foo', 'bar'), ('spam', 'eggs')))
Jeśli podasz zarówno files
i data
, to zależy od wartości z data
co zostanie użyte do utworzenia treści POST. Jeśli data
jest łańcuchem, tylko będzie on użyty; w przeciwnym razie stosowane są oba typy: data
i , z pierwszymi wymienionymi elementami w data
.
Spowoduje to zakodowanie dowolnej rzeczy wysłanej do 'files' jako rzeczywistego parametru pliku w kodowaniu wieloczęściowym. To nie stworzy ścisłej postaci, ale zamiast formularza z wszystkimi parametrami pliku. Zobacz [to] (https://github.com/kennethreitz/requests/issues/1081) w celach informacyjnych. –
@ sigmavirus24: Interfejs API zapytań ewoluował odkąd to opublikowałem; pozwól mi zbadać, czy to wymaga teraz aktualizacji. W każdym razie ten zakątek interfejsu API [od jakiegoś czasu wymaga przeglądu] (https://github.com/kennethreitz/requests/issues/935). –
przeprosiny. StackOverflow umieścił to na górze i zapomniałem reorganizacji pytań i muszę spojrzeć na daty odpowiedzi/zapytał. –
Ponieważ poprzednie odpowiedzi zostały napisane, prośby się zmieniły. Spójrz na numer bug thread at Github, aby uzyskać więcej szczegółów i na przykład this comment.
W skrócie, parametr plików zajmuje dict
z kluczem to nazwa pola formularza i wartość jest albo ciąg lub 2, 3 lub 4-length krotki, jak opisano w sekcji POST a Multipart-Encoded File we wnioskach Szybki start:
>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
w powyższym krotka składa się w następujący sposób:
(filename, data, content_type, headers)
Jeśli wartość jest po prostu ciągiem znaków, nazwa pliku będzie taka sama jak klucz, jak w poniższym przykładzie:
>>> files = {'obvius_session_id': '72c2b6f406cdabd578c5fd7598557c52'}
Content-Disposition: form-data; name="obvius_session_id"; filename="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
Jeśli wartość jest krotka i pierwszy wpis jest None
własność pliku nie zostaną uwzględnione:
>>> files = {'obvius_session_id': (None, '72c2b6f406cdabd578c5fd7598557c52')}
Content-Disposition: form-data; name="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
Co zrobić, jeśli musisz odróżnić 'name' i' filename', ale także mieć wiele pól o tej samej nazwie? – Michael
Mam problem z symulacją jako @Michael. Czy możesz rzucić okiem na to pytanie i coś zasugerować? [link] (http://stackoverflow.com/questions/30683352/how-to-upload-multipart-encode-file-and-form-data-as-a-payload) – Shaardool
czy ktoś rozwiązał ten problem z wieloma polami o tej samej nazwie? – user3131037
Trzeba użyć parametru files
wysłać wieloczęściowy żądanie formularz POST, nawet jeśli nie trzeba przesyłać żadnych plików.
Z pierwotnego requests źródła:
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.
Najprostszym wieloczęściowy żądanie formularz, który zawiera oba pliki do przesłania i pól formularza będzie wyglądać następująco:
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)
☝ Uwaga pusty łańcuch jako pierwszy element krotki dla pól zwykłego tekstu - jest to element zastępczy dla pola nazwy pliku, który jest używany tylko do przesyłania plików, ale dla pola tekstowego pusty symbol zastępczy musi być obecny w kolejności dla danych, które należy złożyć.
Jeśli ten API nie jest wystarczająco pythonic dla Ciebie, lub jeśli trzeba pisać wiele pól o tej samej nazwie, a następnie rozważyć użycie requests toolbelt (
pip install requests_toolbelt
), który stanowi rozszerzenie modułu
core requests, który zapewnia wsparcie dla pliku przesyłaj strumieniowo, a także
MultipartEncoder, który może być używany zamiast
files
i który przyjmuje parametry zarówno jako słowniki, jak i krotki.
MultipartEncoder
może być używany zarówno w przypadku żądań wieloczęściowych z faktycznymi polami przesyłania, jak i bez nich. Musi być przypisany do parametru 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})
Jeśli chcesz wysłać wiele pól o tej samej nazwie, lub jeśli kolejność pól formularza jest ważne, to krotka lub lista może być stosowany zamiast słownika, czyli:
multipart_data = MultipartEncoder(
fields=(
('action', 'store'),
('path', '/path1'),
('path', '/path2'),
('path', '/path3'),
)
)
Dziękuję za to. Kolejność kluczy była dla mnie ważna, a to bardzo pomogło. – Splendor
Niesamowite. Niewytłumaczalnie, api, z którym pracuję, wymaga dwóch różnych wartości dla tego samego klucza. To jest niesamowite. Dziękuję Ci. – ajon
@ccpizza, co właściwie oznacza ta linia? > "(" file.py ", otwórz (" file.py "," rb ")," text/plain ")". To nie działa dla mnie :( –
twoje pytanie nie jest jasne. Co chcesz osiągnąć? Czy chcesz wysłać "wieloczęściowy/formularz danych" bez przesyłania pliku w formularzu? –
Fakt, że parametr 'files' jest używany w obu przypadkach, to bardzo zły interfejs API. Zrobiłem problem pod tytułem [Wysyłanie wieloczęściowych danych - potrzebujemy lepszego interfejsu API] (https://github.com/kennethreitz/requests/issues/935), aby to naprawić. Jeśli zgadzasz się, że użycie parametru 'files' do wysyłania danych mulitpart jest w najlepszym przypadku mylące, poproś o zmianę interfejsu API w powyższym wydaniu. –
@PiotrDobrogost, że problem został zamknięty. Nie zachęcaj ludzi do komentowania zamkniętych spraw, istotnych lub nie. –