Python でリクエストとともに「multipart/form-data」を送信するにはどうすればよいでしょうか? 質問する

Python でリクエストとともに「multipart/form-data」を送信するにはどうすればよいでしょうか? 質問する

Python で送信するmultipart/form-dataにはどうすればいいですかrequests? ファイルの送信方法は理解できますが、この方法でフォーム データを送信する方法が理解できません。

ベストアンサー1

files基本的に、パラメータ (辞書)を指定すると、POSTではなく POSTrequestsが送信されます。ただし、その辞書内の実際のファイルを使用することに限定されるわけではありません。multipart/form-dataapplication/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-Typefilesrequests

さらに良いことに、単一の文字列またはバイト オブジェクトの代わりにタプルを使用することで、各部分のファイル名、コンテンツ タイプ、および追加のヘッダーをさらに制御できます。タプルには、ファイル名、コンテンツ、オプションのコンテンツ タイプ、およびオプションの追加のヘッダーの辞書の 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によって異なります。が文字列の場合は、それのみが使用されます。それ以外の場合はと の両方が使用され、 の要素が最初にリストされます。datadatadatafilesdata

素晴らしい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

おすすめ記事