313

Pythonでmultipart/form-datawithを送信するには? requestsファイルの送信方法はわかりましたが、この方法でフォームデータを送信する方法がわかりません。

4

13 に答える 13

281

基本的に、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'}

さらに良いことに、単一の文字列またはバイト オブジェクトの代わりにタプルを使用して、各パーツのファイル名、コンテンツ タイプ、および追加のヘッダーをさらに制御できます。タプルには 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を含む優れたプロジェクトもあります。パラメータと同じフォーマットでフィールド定義を取りますが、 とは異なり、デフォルトでファイル名パラメータを設定しません。さらに、開いているファイル オブジェクトからリクエストをストリーミングできます。ここで、最初にメモリ内にリクエスト ボディを構築します。filesrequestsrequests

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

于 2012-09-12T09:59:56.113 に答える
123

以前の回答のいくつかが書かれてから、リクエストが変更されました。詳細については、Github のこの問題を参照してください。例については、このコメントを参照してください。

つまり、filesパラメーターは、キーがフォーム フィールドの名前で、値が文字列または長さ 2、3、または 4 のタプルのいずれかであるディクショナリを取りますクイックスタート:

>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}

上記では、タプルは次のように構成されます。

(filename, data, content_type, headers)

値が単なる文字列の場合、ファイル名は次のようにキーと同じになります。

>>> files = {'obvius_session_id': '72c2b6f406cdabd578c5fd7598557c52'}

Content-Disposition: form-data; name="obvius_session_id"; filename="obvius_session_id"
Content-Type: application/octet-stream

72c2b6f406cdabd578c5fd7598557c52

値がタプルで、最初のエントリがNonefilename プロパティである場合、含まれません:

>>> files = {'obvius_session_id': (None, '72c2b6f406cdabd578c5fd7598557c52')}

Content-Disposition: form-data; name="obvius_session_id"
Content-Type: application/octet-stream

72c2b6f406cdabd578c5fd7598557c52
于 2014-04-09T21:50:45.973 に答える
20

以下は、リクエストを使用して追加のパラメーターを含む 1 つのファイルをアップロードするための簡単なコード スニペットです。

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)

コンテンツ タイプを明示的に指定する必要はないことに注意してください。

注: 上記の回答のいずれかにコメントしたかったのですが、評判が低いためにコメントできなかったため、ここに新しい回答を作成しました。

于 2019-01-23T21:59:54.980 に答える
0

これは、マルチパート リクエストでファイルを送信する 1 つの方法です。

import requests
headers = {"Authorization": "Bearer <token>"}
myfile = 'file.txt'
myfile2 = {'file': (myfile, open(myfile, 'rb'),'application/octet-stream')}
url = 'https://example.com/path'
r = requests.post(url, files=myfile2, headers=headers,verify=False)
print(r.content)

その他のアプローチ

import requests

url = "https://example.com/path"

payload={}
files=[
  ('file',('file',open('/path/to/file','rb'),'application/octet-stream'))
]
headers = {
  'Authorization': 'Bearer <token>'
}

response = requests.request("POST", url, headers=headers, data=payload, files=files)

print(response.text)

私は両方をテストしましたが、両方とも正常に動作します。

于 2021-11-26T12:10:44.080 に答える
-1

Python 3のリクエストモジュールを使用してURL_serverにリクエストを送信しようとしています.これは私にとってはうまくいきます:

# -*- coding: utf-8 *-*
import json, requests

URL_SERVER_TO_POST_DATA = "URL_to_send_POST_request"
HEADERS = {"Content-Type" : "multipart/form-data;"}

def getPointsCC_Function():
  file_data = {
      'var1': (None, "valueOfYourVariable_1"),
      'var2': (None, "valueOfYourVariable_2")
  }

  try:
    resElastic = requests.post(URL_GET_BALANCE, files=file_data)
    res = resElastic.json()
  except Exception as e:
    print(e)

  print (json.dumps(res, indent=4, sort_keys=True))

getPointsCC_Function()

どこ:

  • URL_SERVER_TO_POST_DATA = データを送信するサーバー
  • HEADERS = 送信されたヘッダー
  • file_data = パラメータが送信されました
于 2020-08-26T23:56:17.073 に答える