python meminta pengunggahan file

125

Saya melakukan tugas sederhana mengunggah file menggunakan pustaka permintaan Python. Saya mencari Stack Overflow dan sepertinya tidak ada yang memiliki masalah yang sama, yaitu file tidak diterima oleh server:

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)

Saya mengisi nilai kata kunci 'upload_file' dengan nama file saya, karena jika saya biarkan kosong, katanya

Error - You must select a file to upload!

Dan sekarang saya mengerti

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

Yang muncul hanya jika file tersebut kosong. Jadi saya terjebak bagaimana mengirim file saya dengan sukses. Saya tahu bahwa file tersebut berfungsi karena jika saya membuka situs web ini dan mengisi formulir secara manual, ia mengembalikan daftar objek yang cocok, yang saya cari. Saya sangat menghargai semua petunjuk.

Beberapa utas lain terkait (tetapi tidak menjawab masalah saya):

scichris.dll
sumber

Jawaban:

211

Jika upload_filedimaksudkan sebagai file, gunakan:

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

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

dan requestsakan mengirimkan bentuk badan POST multi-bagian dengan upload_filebidang disetel ke konten file.txtfile.

Nama file akan dimasukkan dalam tajuk pantomim untuk bidang tertentu:

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

Perhatikan filename="file.txt"parameternya.

Anda dapat menggunakan tupel untuk nilai filespemetaan, dengan antara 2 dan 4 elemen, jika Anda membutuhkan lebih banyak kontrol. Elemen pertama adalah nama file, diikuti oleh konten, dan nilai header tipe konten opsional dan pemetaan opsional dari header tambahan:

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

Ini menetapkan nama file dan jenis konten alternatif, tanpa menyertakan header opsional.

Jika yang Anda maksud adalah seluruh isi POST yang akan diambil dari sebuah file (tanpa bidang lain yang ditentukan), maka jangan gunakan filesparameter, cukup posting file tersebut secara langsung sebagai data. Kemudian Anda mungkin ingin menyetel Content-Typetajuk juga, karena tidak ada yang akan disetel sebaliknya. Lihat permintaan Python - data POST dari file .

Martijn Pieters
sumber
Hai, Bagaimana cara mengirim banyak file dengan nama yang sama? Seperti 'kemelekatan' misalnya.
William Wino
4
@William: Anda dapat menggunakan urutan tuple 2-nilai juga, yang memungkinkan nama field Anda menggunakan kembali: files = [('attachment', open('attachment1.txt', 'rb')), ('attachment', open('attachment2.txt', 'rb'))]. Setiap tupel adalah sepasang kunci dan nilai.
Martijn Pieters
2
Anda juga bisa menggunakan files={'file':('nameoffile',open('namoffile','rb'),'Content-Type':'text/html','other header'),'file2':('nameoffile2',open('nameoffile2','rb'),'Content-Type':'application/xml','other header')}tetapi Jika file = {} digunakan maka headers = {'Content-Type': 'blah blah'} tidak boleh digunakan! -> @ martijn-pieters: karena multipart / form-data Content-Type harus menyertakan nilai batas yang digunakan untuk menggambarkan bagian-bagian dalam badan posting. Tidak menyetel header Jenis Konten memastikan bahwa permintaan menyetelnya ke nilai yang benar.
zaki
1
@MartijnPieters Apakah ini tidak berisiko membocorkan file? Apakah requeststutup itu?
Matt Messersmith
4
@MattMessersmith: tidak, itu belum ditutup. Jika Anda ingin menutup file, gunakan with open(...) as fobj:dan gunakan fobjdalam filespemetaan.
Martijn Pieters
36

(2018) pustaka permintaan python baru telah menyederhanakan proses ini, kita dapat menggunakan variabel 'file' untuk memberi sinyal bahwa kita ingin mengunggah file yang dikodekan multipart

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

r = requests.post(url, files=files)
r.text
kucing awam
sumber
3
Apakah pustaka permintaan secara otomatis menutup file?
Demetris
1
halo, sudah lama sejak saya menggunakan perpustakaan ini. pertanyaan yang bagus. bisakah Anda membantu saya dan yang lainnya dengan mengetik lsof | grep "nama file" dan bagikan hasil Anda dengan kami? terima kasih :)
laycat
1
Dengan penggunaan lsof, tampaknya file tetap terbuka, atau setidaknya, begitulah cara saya menafsirkan hasil berikut. Sebelumnya, menjalankan opentidak ada record dalam lsoftabel tentang filename. Kemudian setelah opendijalankan, beberapa record muncul dengan readakses. Setelah menjalankan requests.post, catatan masih ada yang menunjukkan bahwa file tersebut tidak ditutup.
Demetris
23

Unggahan Klien

Jika Anda ingin mengunggah satu file dengan requestspustaka Python , maka permintaan lib mendukung unggahan streaming , yang memungkinkan Anda mengirim file atau streaming besar tanpa membaca ke dalam memori .

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

Sisi server

Kemudian simpan file di server.pysamping sedemikian rupa sehingga menyimpan aliran ke dalam file tanpa memuat ke memori. Berikut adalah contoh penggunaan upload file 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

Atau gunakan Penguraian Data Formulir werkzeug seperti yang disebutkan dalam perbaikan untuk masalah " unggahan file besar memakan memori " untuk menghindari penggunaan memori secara tidak efisien pada unggahan file besar (st 22 GiB file dalam ~ 60 detik. Penggunaan memori konstan sekitar 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
gihanchanuka
sumber
0

Di Ubuntu Anda dapat menerapkan cara ini,

untuk menyimpan file di beberapa lokasi (sementara) dan kemudian membuka dan mengirimkannya ke 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)
Harshit Trivedi
sumber
apa nilai datavariabel?
am.rez
bisa apa saja seperti nama pengguna, saya baru saja menunjukkan cara mengunggah file ke REST apis
Harshit Trivedi