python dosya yüklemesini ister


125

Python istek kitaplığını kullanarak basit bir dosya yükleme görevi gerçekleştiriyorum. Yığın Taşması'nı araştırdım ve hiç kimse aynı soruna sahip görünmüyordu, yani dosyanın sunucu tarafından alınmaması:

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' anahtar kelimesinin değerini dosya adımla dolduruyorum çünkü boş bırakırsam

Error - You must select a file to upload!

Ve şimdi anlıyorum

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

Bu sadece dosya boşsa ortaya çıkar. Bu yüzden dosyamı nasıl başarılı bir şekilde göndereceğim konusunda takılı kaldım. Dosyanın çalıştığını biliyorum çünkü bu web sitesine gidersem ve formu manuel olarak doldurursam, eşleşen nesnelerin güzel bir listesini döndürür, bu da peşinde olduğum şeydir. Tüm ipuçlarını gerçekten takdir ediyorum.

Diğer bazı konularla ilgili (ancak sorunuma cevap vermeyen):

Yanıtlar:


211

Eğer upload_filedosya, kullanımı olması gerekiyordu:

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

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

ve dosyanın içeriğine ayarlanmış alanla requestsbirlikte çok parçalı bir form POST gövdesi gönderecektir .upload_filefile.txt

Dosya adı, belirli alan için mime başlığına dahil edilecektir:

>>> 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"Parametreyi not edin .

Daha filesfazla kontrole ihtiyacınız varsa , eşleme değeri için 2 ila 4 öğe içeren bir demet kullanabilirsiniz . İlk öğe, dosya adı, ardından içerik ve isteğe bağlı bir içerik türü başlık değeri ve ek başlıkların isteğe bağlı bir eşlemesidir:

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

Bu, isteğe bağlı üstbilgileri dışarıda bırakarak alternatif bir dosya adı ve içerik türü belirler.

Tüm POST gövdesinin bir dosyadan alınmasını kastediyorsanız (başka alan belirtilmeden), o zaman filesparametreyi kullanmayın , dosyayı doğrudan data. Content-TypeAksi takdirde hiçbiri ayarlanmayacağı için bir başlık da ayarlamak isteyebilirsiniz . Python istekleri - Bir dosyadan POST verileri bölümüne bakın .


Merhaba, Aynı adı paylaşan birden çok dosyayı nasıl gönderirim? Örneğin 'ek' gibi.
William Wino

4
@William: Eğer yeniden kullanım alan adlarını sağlayan, çok 2-değer dizilerini dizisi kullanabilirsiniz: files = [('attachment', open('attachment1.txt', 'rb')), ('attachment', open('attachment2.txt', 'rb'))]. Her demet bir anahtar ve değer çiftidir.
Martijn Pieters

2
Ayrıca kullanabilirsiniz, files={'file':('nameoffile',open('namoffile','rb'),'Content-Type':'text/html','other header'),'file2':('nameoffile2',open('nameoffile2','rb'),'Content-Type':'application/xml','other header')}ancak files = {} kullanılırsa, headers = {'Content-Type': 'blah blah'} kullanılmamalıdır! -> @ martijn-pieters: çünkü multipart / form-data Content-Type, post gövdesindeki parçaları sınırlandırmak için kullanılan sınır değerini içermelidir. Content-Type başlığının ayarlanmaması, isteklerin onu doğru değere ayarlamasını sağlar.
zaki

1
@MartijnPieters Bu, dosyayı sızdırmaz mı? Kapanır mı requests?
Matt Messersmith

4
@MattMessersmith: hayır, kapalı değil. Dosyayı kapatmak istiyorsanız , haritalamada kullanın with open(...) as fobj:ve kullanın . fobjfiles
Martijn Pieters

36

(2018) yeni python istek kitaplığı bu süreci basitleştirdi, çok parçalı kodlanmış bir dosya yüklemek istediğimizi belirtmek için 'dosyalar' değişkenini kullanabiliriz

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

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

3
Kitaplık istekleri dosyayı otomatik olarak kapatıyor mu?
Demetris

1
merhaba, bu kütüphaneyi kullandığımdan beri bir süredir. güzel soru. lsof yazarak bana ve diğerlerine yardım edebilir misin | grep "dosya adı" ve sonuçlarınızı bizimle paylaşın? teşekkürler :)
laycat

1
Kullanımı ile lsof, dosya açık kalıyor gibi görünüyor veya en azından aşağıdaki sonuçları böyle yorumluyorum. Önce, koşu openhiçbir kayıt yoktur lsofyaklaşık masaya filename. Ardından openyürütüldükten sonra, readerişime sahip birden çok kayıt görünür . requests.postDosyasını çalıştırdıktan sonra , kayıtlar hala oradadır ve dosyanın kapanmadığını gösterir.
Demetris

23

İstemci Yüklemesi

Python requestskitaplığı ile tek bir dosya yüklemek istiyorsanız , lib , belleğe okumadan büyük dosyalar veya akışlar göndermenize olanak tanıyan akış yüklemelerini destekler .

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

Sunucu Tarafı

Ardından dosyayı server.py, belleğe yüklemeden akışı dosyaya kaydedecek şekilde yan tarafta saklayın. Aşağıda, Flask dosya yüklemelerinin kullanımına bir örnek verilmiştir .

@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

Ya Kullanım Form Verilerini ayrıştırma werkzeug "nin soruna yönelik bir düzeltmenin belirtildiği gibi büyük dosya yükleme, bellek harcamadan amacıyla" büyük dosyalar upload verimsiz bellek kullanmaktan kaçının ~ 60 saniye içinde (st 22 GiB dosyasını. Bellek kullanımı sabit yaklaşık altındadır 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'da bu şekilde uygulayabilirsiniz,

dosyayı bir konuma (geçici) kaydetmek ve ardından açıp API'ye göndermek için

      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)

datadeğişkenin değeri nedir?
am.rez

kullanıcı adı gibi herhangi bir şey olabilir, dosyaları REST apis'e nasıl yükleyeceğimi az önce gösterdim
Harshit Trivedi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.