¿Cómo cargar un archivo con solicitudes de Python?

Resuelto scichris asked hace 10 años • 10 respuestas

Estoy realizando una tarea simple de cargar un archivo usando la biblioteca de solicitudes de Python. Busqué Stack Overflow y nadie parecía tener el mismo problema, es decir, que el servidor no recibe el archivo:

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)

Estoy completando el valor de la palabra clave 'upload_file' con mi nombre de archivo, porque si lo dejo en blanco, dice

Error - You must select a file to upload!

Y ahora entiendo

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

Que aparece sólo si el archivo está vacío. Así que no sé cómo enviar mi archivo correctamente. Sé que el archivo funciona porque si voy a este sitio web y completo el formulario manualmente, me devuelve una buena lista de objetos coincidentes, que es lo que busco. Realmente agradecería todas las sugerencias.

Algunos otros hilos relacionados (pero no responden a mi problema):

  • Enviar archivo usando POST desde un script de Python
  • http://docs.python-requests.org/en/latest/user/quickstart/#response-content
  • Subir archivos usando solicitudes y enviar datos adicionales
  • http://docs.python-requests.org/en/latest/user/advanced/#body-content-workflow
scichris avatar Mar 22 '14 01:03 scichris
Aceptado

Si upload_filepretende ser el archivo, use:

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

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

y requestsenviará un cuerpo POST de formulario de varias partes con el upload_filecampo configurado para el contenido del file.txtarchivo.

El nombre del archivo se incluirá en el encabezado MIME del 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--

Tenga en cuenta el filename="file.txt"parámetro.

Puedes usar una tupla para el filesvalor del mapeo, con entre 2 y 4 elementos, si necesitas más control. El primer elemento es el nombre del archivo, seguido del contenido, un valor de encabezado de tipo de contenido opcional y una asignación opcional de encabezados adicionales:

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

Esto establece un nombre de archivo y un tipo de contenido alternativos, omitiendo los encabezados opcionales.

Si quiere decir que todo el cuerpo POST se tomará de un archivo (sin otros campos especificados), entonces no use el filesparámetro, simplemente publique el archivo directamente como data. Es posible que también desees establecer un Content-Typeencabezado, ya que de lo contrario no se establecerá ninguno. Consulte Solicitudes de Python: POST datos desde un archivo .

Martijn Pieters avatar Mar 21 '2014 19:03 Martijn Pieters

(2018) la nueva biblioteca de solicitudes de Python ha simplificado este proceso, podemos usar la variable 'archivos' para indicar que queremos cargar un archivo codificado en varias partes

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

r = requests.post(url, files=files)
r.text
laycat avatar Sep 19 '2018 00:09 laycat

Subir cliente

Si desea cargar un solo archivo con requestsla biblioteca de Python, entonces Requests lib admite cargas de transmisión , lo que le permite enviar archivos o transmisiones de gran tamaño sin leer en la memoria .

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

Lado del servidor

Luego almacene el archivo en un server.pylado de manera que guarde la secuencia en un archivo sin cargarlo en la memoria. A continuación se muestra un ejemplo del uso de cargas de archivos de 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

O utilice werkzeug Form Data Parsing como se menciona en una solución para el problema de " cargas de archivos grandes que consumen memoria " para evitar el uso ineficiente de la memoria en la carga de archivos grandes (archivo de 22 GiB en ~60 segundos. El uso de la memoria es constante en aproximadamente 13 MB.).

@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 avatar Feb 24 '2019 22:02 gihanchanuka