pythonはファイルのアップロードを要求します


123

Pythonリクエストライブラリを使用してファイルをアップロードする簡単なタスクを実行しています。私はスタックオーバーフローを検索しましたが、誰も同じ問題を抱えているようには見えませんでした。つまり、ファイルがサーバーによって受信されないということです。

import requests
url='http://nesssi.cacr.caltech.edu/cgi-bin/getmulticonedb_release2.cgi/post'
files={'files': open('file.txt','rb')}
values={'upload_file' : 'file.txt' , 'DB':'photcat' , 'OUT':'csv' , 'SHORT':'short'}
r=requests.post(url,files=files,data=values)

「upload_file」キーワードの値にファイル名を入力します。空白のままにすると、

Error - You must select a file to upload!

そして今私は得る

File  file.txt  of size    bytes is  uploaded successfully!
Query service results:  There were 0 lines.

これは、ファイルが空の場合にのみ表示されます。そのため、ファイルを正常に送信する方法に悩まされています。このWebサイトにアクセスしてフォームに手動で入力すると、一致したオブジェクトの素晴らしいリストが返されるため、ファイルが機能することはわかっています。すべてのヒントに本当に感謝します。

関連する他のいくつかのスレッド(ただし、私の問題には答えていません):

回答:


210

upload_fileファイルとする場合は、次を使用します。

files = {'upload_file': open('file.txt','rb')}
values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'}

r = requests.post(url, files=files, data=values)

そしてrequestsupload_fileフィールドがfile.txtファイルの内容に設定されたマルチパートフォームPOST本文を送信します。

ファイル名は、特定のフィールドのMIMEヘッダーに含まれます。

>>> import requests
>>> open('file.txt', 'wb')  # create an empty demo file
<_io.BufferedWriter name='file.txt'>
>>> files = {'upload_file': open('file.txt', 'rb')}
>>> print(requests.Request('POST', 'http://example.com', files=files).prepare().body.decode('ascii'))
--c226ce13d09842658ffbd31e0563c6bd
Content-Disposition: form-data; name="upload_file"; filename="file.txt"


--c226ce13d09842658ffbd31e0563c6bd--

filename="file.txt"パラメータに注意してください。

filesさらに制御が必要な場合は、マッピング値に2〜4要素のタプルを使用できます。最初の要素はファイル名で、その後にコンテンツ、オプションのcontent-typeヘッダー値、オプションの追加ヘッダーのマッピングが続きます。

files = {'upload_file': ('foobar.txt', open('file.txt','rb'), 'text/x-spam')}

これにより、代替のファイル名とコンテンツタイプが設定され、オプションのヘッダーは除外されます。

(他のフィールドが指定されていない)ファイルからPOST本文全体を取得することを意味している場合は、filesパラメーターを使用せず、ファイルを直接として投稿してくださいdataContent-Typeそれ以外の場合は何も設定されないため、ヘッダーも設定することができます。Pythonリクエスト-ファイルからのPOSTデータを参照してください。


こんにちは、どうすれば同じ名前を共有する複数のファイルを送信できますか?たとえば「添付ファイル」のように。
William Wino

4
@William:2値のタプルのシーケンスも使用できるため、フィールド名を再利用できますfiles = [('attachment', open('attachment1.txt', 'rb')), ('attachment', open('attachment2.txt', 'rb'))]。各タプルはキーと値のペアです。
Martijn Pieters

2
また、使用することもできますfiles={'file':('nameoffile',open('namoffile','rb'),'Content-Type':'text/html','other header'),'file2':('nameoffile2',open('nameoffile2','rb'),'Content-Type':'application/xml','other header')}が、files = {}を使用する場合、headers = {'Content-Type': 'blah blah'}は使用しないでください。-> @ martijn-pieters:multipart / form-data Content-Typeには、ポストボディのパーツのデリニエーションに使用される境界値を含める必要があるため。Content-Typeヘッダーを設定しないことで、リクエストでヘッダーが正しい値に設定されるようになります。

1
@MartijnPietersこれはファイルをリークするリスクがありませんか?いrequests、それは近いですか?
Matt Messersmith、

4
@MattMessersmith:いいえ、閉鎖されていません。ファイルを閉じたい場合は、マッピングでwith open(...) as fobj:使用fobjしてくださいfiles
Martijn Pieters

35

(2018)新しいpythonリクエストライブラリはこのプロセスを簡略化しました。「files」変数を使用して、マルチパートエンコードされたファイルをアップロードすることを通知できます

url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}

r = requests.post(url, files=files)
r.text

3
リクエストライブラリはファイルを自動的に閉じますか?
Demetris、

1
こんにちは、私がこのライブラリを使用してからしばらく経ちました。いい質問だ。lsofと入力して、私と他の人に手を貸してくれませんか?「ファイル名」をgrepして、結果を私たちと共有しますか?おかげで:)
laycat '11 / 10/19

1
を使用するとlsof、ファイルが開いたままになるようですが、少なくとも、これが次の結果の解釈方法です。以前、を実行すると、に関するopenレコードがlsofテーブルにありませんfilename。次に、openが実行された後、複数のレコードがreadアクセス権とともに表示されます。を実行した後requests.postも、ファイルは閉じられなかったことを示すレコードが残っています。
Demetris

23

クライアントのアップロード

Python requestsライブラリを使用して単一のファイルをアップロードする場合、リクエストlib はストリーミングアップロードをサポートします。これにより、メモリに読み込まずに大きなファイルやストリームを送信できます。

with open('massive-body', 'rb') as f:
    requests.post('http://some.url/streamed', data=f)

サーバ側

次にserver.py、メモリを読み込まずにストリームをファイルに保存するように、ファイルを側面に保存します。以下は、Flaskファイルのアップロードを使用した例です

@app.route("/upload", methods=['POST'])
def upload_file():
    from werkzeug.datastructures import FileStorage
    FileStorage(request.stream).save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
    return 'OK', 200

または、「大きなファイルのアップロードがメモリを消費する」の問題の修正で言及されているように、werkzeugフォームデータ解析を使用して、大きなファイルのアップロードでメモリが非効率的に使用されるのを防ぎます(最大22 GiBのファイル、60秒以内。メモリの使用量は約一定です) 13 MiB)。

@app.route("/upload", methods=['POST'])
def upload_file():
    def custom_stream_factory(total_content_length, filename, content_type, content_length=None):
        import tempfile
        tmpfile = tempfile.NamedTemporaryFile('wb+', prefix='flaskapp', suffix='.nc')
        app.logger.info("start receiving file ... filename => " + str(tmpfile.name))
        return tmpfile

    import werkzeug, flask
    stream, form, files = werkzeug.formparser.parse_form_data(flask.request.environ, stream_factory=custom_stream_factory)
    for fil in files.values():
        app.logger.info(" ".join(["saved form name", fil.name, "submitted as", fil.filename, "to temporary file", fil.stream.name]))
        # Do whatever with stored file at `fil.stream.name`
    return 'OK', 200

0

Ubuntuでは、このように適用できます、

ある場所(一時)にファイルを保存してから開いてAPIに送信する

      path = default_storage.save('static/tmp/' + f1.name, ContentFile(f1.read()))
      path12 = os.path.join(os.getcwd(), "static/tmp/" + f1.name)
      data={} #can be anything u want to pass along with File
      file1 = open(path12, 'rb')
      header = {"Content-Disposition": "attachment; filename=" + f1.name, "Authorization": "JWT " + token}
       res= requests.post(url,data,header)

data変数の値は何ですか?
am.rez

ユーザー名のようなものにすることができます
。RESTAPIに
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.