web-dev-qa-db-ja.com

Pythonでリクエストと "multipart / form-data"を送信する方法?

Pythonでリクエストと共にmultipart/form-dataを送信するにはどうすればいいですか?ファイルの送信方法はわかりますが、この方法でフォームデータを送信する方法はわかりません。

163
agrynchuk

基本的に、filesパラメータ(辞書)を指定した場合、requestsmultipart/form-data POSTの代わりにapplication/x-www-form-urlencoded POSTを送信します。ただし、その辞書で実際のファイルを使用することに制限されていません。

>>> 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'}

さらに良いことには、単一の文字列やbytesオブジェクトの代わりにTupleを使うことで、各部分のファイル名、コンテンツタイプ、追加のヘッダをさらに制御することができます。 Tupleは2から4の要素を含むことが期待されています。ファイル名、コンテンツ、オプションでコンテンツタイプ、およびその他のヘッダーのオプションの辞書。

ファイル名としてNoneを使用してTuple形式を使用すると、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')), ('spam', (None, 'eggs'))))

filesdataの両方を指定した場合、POST本体の作成に使用される値は、dataによって異なります。 dataが文字列の場合は、それだけが使用されます。それ以外の場合は、datafilesの両方が使用され、data内の要素が最初にリストされます。

高度なマルチパートサポート を含む優れたrequests-toolbeltプロジェクトもあります。これはfilesパラメータと同じ形式のフィールド定義を取りますが、requestsとは異なり、デフォルトでfilenameパラメータを設定しません。さらに、開いているファイルオブジェクトから要求をストリーミングすることもできます。この場合、requestsは最初に要求本文をメモリ内に構築します。

109
Martijn Pieters

前の答えが書かれてから、要求は変わりました。 Githubの バグスレッドを見てください 詳細については このコメント 例については/ /をご覧ください。

簡単に言うと、filesパラメータはdictを取ります。キーはフォームフィールドの名前、値は文字列、または長さ2、3、または4のいずれかのタプルのいずれかです。 POSTマルチパートエンコードファイル リクエストのクイックスタートでは、

>>> 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

値がTupleで、最初のエントリがNoneの場合、filenameプロパティは含まれません。

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

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

72c2b6f406cdabd578c5fd7598557c52
95
runejuhl

サイトのHTMLにあるアップロードファイルのname属性を使用する必要があります。例:

autocomplete="off" name="image">

name="image">が見えますか?あなたはファイルをアップロードするためのサイトのHTMLでそれを見つけることができます。 Multipart/form-dataでファイルをアップロードするためにそれを使う必要があります

スクリプト:

import requests

site = 'https://prnt.sc/upload.php' # the site where you upload the file
filename = 'image.jpg'  # name example

ここでは、画像の場所に、アップロードファイルの名前をHTMLで追加します。

up = {'image':(filename, open(filename, 'rb'), "multipart/form-data")}

アップロード時にボタンをクリックしてアップロードする必要がある場合は、次のように使用できます。

data = {
     "Button" : "Submit",
}

それから要求を始めなさい

request = requests.post(site, files=up, data=data)

そして、ファイルが正常にアップロードされました

4
Skiller Dz

リクエストを使用して追加のパラメータを持つ単一のファイルをアップロードする簡単なコードスニペットは次のとおりです。

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)

コンテンツタイプを明示的に指定する必要はありません。

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

1
Jainik

これは、マルチパートフォームデータとして1つの大きな単一ファイルをアップロードするのに必要なPythonスニペットです。 NodeJs Multerミドルウェアがサーバー側で動作している。

import requests
latest_file = 'path/to/file'
url = "http://httpbin.org/apiToUpload"
files = {'fieldName': open(latest_file, 'rb')}
r = requests.put(url, files=files)

サーバーサイドの場合は、multerのドキュメントを確認してください。 https://github.com/expressjs/multer ここでは、フィールドシングル( 'fieldName')は次のとおりです。次のように、単一のファイルを受け取るために使用されます。

var upload = multer().single('fieldName');
0
vinaymk