web-dev-qa-db-ja.com

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

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

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サイトにアクセスしてフォームに手動で入力すると、一致するオブジェクトのニースリストが返されるため、ファイルが機能することはわかっています。すべてのヒントを本当に感謝しています。

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

77
scichris

upload_fileがファイルである場合、次を使用します。

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

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

requestsは、upload_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マッピング値にTupleを使用して、2〜4個の要素を使用できます。最初の要素はファイル名で、その後にコンテンツ、オプションのコンテンツタイプヘッダー値、追加ヘッダーのオプションマッピングが続きます。

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

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

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

148
Martijn Pieters

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

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

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

クライアントの更新

Python requestsライブラリを使用して単一のファイルをアップロードする場合、lib ストリーミングアップロードをサポート を要求します。これにより、send large filesまたはストリームメモリへの読み込みなし

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

サーバ側

次に、メモリにロードせずにストリームをファイルに保存するように、server.py側にファイルを保存します。 Flask file uploads を使用した例を次に示します。

@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 Form Data Parsing を使用して、avoid大きなファイルのアップロードでメモリを非効率的に使用する(〜60秒でst 22 GiBファイル。メモリ使用量は約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
9
gihanchanuka