python solicita upload de arquivo


123

Estou executando uma tarefa simples de upload de um arquivo usando a biblioteca de solicitações Python. Pesquisei Stack Overflow e ninguém parecia ter o mesmo problema, ou seja, que o arquivo não é recebido pelo servidor:

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)

Estou preenchendo o valor da palavra-chave 'upload_file' com meu nome de arquivo, porque se eu deixar em branco, ele diz

Error - You must select a file to upload!

E agora eu consigo

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

Que só aparece se o arquivo estiver vazio. Então, estou sem saber como enviar meu arquivo com sucesso. Eu sei que o arquivo funciona porque se eu entrar neste site e preencher manualmente o formulário, ele retorna uma boa lista de objetos correspondentes, que é o que procuro. Eu realmente aprecio todas as dicas.

Alguns outros tópicos relacionados (mas não respondem ao meu problema):

Respostas:


210

Se upload_filefor o arquivo, use:

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

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

e requestsenviará um corpo POST de formulário com várias partes com o upload_filecampo definido para o conteúdo do file.txtarquivo.

O nome do arquivo será incluído no cabeçalho mime do campo específico:

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

Observe o filename="file.txt"parâmetro.

Você pode usar uma tupla para o filesvalor de mapeamento, com entre 2 e 4 elementos, se precisar de mais controle. O primeiro elemento é o nome do arquivo, seguido pelo conteúdo e um valor de cabeçalho opcional do tipo de conteúdo e um mapeamento opcional de cabeçalhos adicionais:

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

Isso define um nome de arquivo alternativo e tipo de conteúdo, deixando de fora os cabeçalhos opcionais.

Se você está querendo que todo o corpo do POST seja obtido de um arquivo (sem outros campos especificados), não use o filesparâmetro, apenas poste o arquivo diretamente como data. Você também pode querer definir um Content-Typecabeçalho, pois nenhum será definido de outra forma. Consulte solicitações Python - dados POST de um arquivo .


Olá, Como faço para enviar vários arquivos com o mesmo nome? Como 'anexo', por exemplo.
William Wino

4
@William: você pode usar uma seqüência de tuplas 2 de valor também, o que permite reutilizar nomes de campos: files = [('attachment', open('attachment1.txt', 'rb')), ('attachment', open('attachment2.txt', 'rb'))]. Cada tupla é um par de chave e valor.
Martijn Pieters

2
Além disso, você também pode usar, files={'file':('nameoffile',open('namoffile','rb'),'Content-Type':'text/html','other header'),'file2':('nameoffile2',open('nameoffile2','rb'),'Content-Type':'application/xml','other header')}mas se files = {} for usado, headers = {'Content-Type': 'blah blah'} não deve ser usado! -> @ martijn-pieters: porque o tipo de conteúdo multipart / form-data deve incluir o valor limite usado para delinear as partes no corpo da postagem. Não definir o cabeçalho Content-Type garante que as solicitações o definam com o valor correto.
zaki de

1
@MartijnPieters Isso não corre o risco de vazar o arquivo? Fecha requests?
Matt Messersmith

4
@MattMessersmith: não, não está fechado. Se você deseja fechar o arquivo, use with open(...) as fobj:e use fobjno filesmapeamento.
Martijn Pieters

35

(2018) a nova biblioteca de solicitações python simplificou esse processo, podemos usar a variável 'arquivos' para sinalizar que queremos fazer o upload de um arquivo codificado em várias partes

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

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

3
A biblioteca de solicitações fecha o arquivo automaticamente?
Demetris

1
Olá, já faz algum tempo desde que usei esta biblioteca. boa pergunta. você poderia ajudar a mim e aos outros digitando lsof | grep "filename" e compartilha seus resultados conosco? obrigado :)
laycat

1
Com o uso de lsof, parece que o arquivo permanece aberto, ou pelo menos é assim que interpreto os seguintes resultados. Antes, rodando o opennão há registro na lsoftabela sobre o filename. Depois de openexecutado, vários registros aparecem com readacesso. Após a execução do requests.post, os registros continuam lá indicando que o arquivo não foi fechado.
Demetris

23

Upload de cliente

Se você deseja fazer upload de um único arquivo com a requestsbiblioteca Python , então o request lib suporta uploads de streaming , que permitem enviar arquivos grandes ou fluxos sem ler na memória .

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

Lado do Servidor

Em seguida, armazene o arquivo server.pylateralmente de forma que salve o fluxo em um arquivo sem carregar na memória. A seguir está um exemplo com o uso de uploads de arquivo 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

Ou use a análise de dados de formulário werkzeug, conforme mencionado em uma correção para o problema de " uploads de arquivos grandes consumindo memória ", a fim de evitar o uso ineficiente da memória no upload de arquivos grandes ( arquivo st 22 GiB em ~ 60 segundos. O uso de memória é constante em cerca de 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

No Ubuntu você pode aplicar desta forma,

para salvar o arquivo em algum local (temporário) e depois abri-lo e enviá-lo para a 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)

qual é o valor da datavariável?
am.rez

pode ser qualquer coisa como nome de usuário, acabei de mostrar como fazer upload de arquivos para REST apis
Harshit Trivedi
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.