Python で送信するmultipart/form-data
にはどうすればいいですかrequests
? ファイルの送信方法は理解できますが、この方法でフォーム データを送信する方法が理解できません。
ベストアンサー1
files
基本的に、パラメータ (辞書)を指定すると、POSTではなく POSTrequests
が送信されます。ただし、その辞書内の実際のファイルを使用することに限定されるわけではありません。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'])
{'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'}
明確に言うと、パラメータを使用するときはヘッダーを設定しないでください。これは、リクエスト本体で使用される値と一致する (一意の) 境界値をヘッダーに指定する必要があるためです。Content-Type
files
requests
さらに良いことに、単一の文字列またはバイト オブジェクトの代わりにタプルを使用することで、各部分のファイル名、コンテンツ タイプ、および追加のヘッダーをさらに制御できます。タプルには、ファイル名、コンテンツ、オプションのコンテンツ タイプ、およびオプションの追加のヘッダーの辞書の 2 ~ 4 個の要素が含まれている必要があります。
None
ファイル名としてタプル形式を使用すると、filename="..."
その部分のリクエストからパラメータが削除されます。
>>> 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
順序付けや同じ名前の複数のフィールドが必要な場合は、2 つの値のタプルのリストにすることもできます。
requests.post(
'http://requestb.in/xucj9exu',
files=(
('foo', (None, 'bar')),
('foo', (None, 'baz')),
('spam', (None, 'eggs')),
)
)
files
との両方を指定した場合、 POST 本文の作成に使用されるものは の値data
によって異なります。が文字列の場合は、それのみが使用されます。それ以外の場合はと の両方が使用され、 の要素が最初にリストされます。data
data
data
files
data
素晴らしいrequests-toolbelt
プロジェクトもあります。高度なマルチパートサポート。 は、パラメータと同じ形式のフィールド定義を受け取りますfiles
が、 とは異なりrequests
、デフォルトではファイル名パラメータを設定しません。さらに、開いているファイル オブジェクトからリクエストをストリーミングすることができ、 はrequests
最初にメモリ内にリクエスト本体を構築します。
from requests_toolbelt.multipart.encoder import MultipartEncoder
mp_encoder = MultipartEncoder(
fields={
'foo': 'bar',
# plain file object, no filename or mime type produces a
# Content-Disposition header with just the part name
'spam': ('spam.txt', open('spam.txt', 'rb'), 'text/plain'),
}
)
r = requests.post(
'http://httpbin.org/post',
data=mp_encoder, # The MultipartEncoder is posted as data, don't use files=...!
# The MultipartEncoder provides the content-type header with the boundary:
headers={'Content-Type': mp_encoder.content_type}
)
フィールドは同じ規則に従います。2 ~ 4 個の要素を持つタプルを使用して、ファイル名、一部の MIME タイプ、または追加のヘッダーを追加します。パラメータとは異なり、タプルを使用しない場合はfiles
デフォルト値の検索は行われません。filename