requests - ¿Cómo enviar un "multipart/form-data" con solicitudes en python?
requests request python (4)
¿Cómo enviar un multipart/form-data
con peticiones en python? Cómo entiendo cómo enviar un archivo, pero no puedo entender cómo enviar los datos del formulario mediante este método.
Básicamente, si especifica un parámetro de files
(un diccionario), las requests
enviarán una POST multipart/form-data
lugar de una application/x-www-form-urlencoded
POST. Sin embargo, no está limitado a usar archivos reales en ese diccionario:
>>> import requests
>>> response = requests.post(''http://httpbin.org/post'', files=dict(foo=''bar''))
>>> response.status_code
200
y httpbin.org le permite saber con qué encabezados ha publicado; en response.json()
tenemos:
>>> from pprint import pprint
>>> pprint(response.json()[''headers''])
{u''Accept'': u''*/*'',
u''Accept-Encoding'': u''gzip, deflate, compress'',
u''Connection'': u''close'',
u''Content-Length'': u''141'',
u''Content-Type'': u''multipart/form-data; boundary=33b4531a79be4b278de5f5688fab7701'',
u''Host'': u''httpbin.org'',
u''User-Agent'': u''python-requests/2.2.1 CPython/2.7.6 Darwin/13.2.0'',
u''X-Request-Id'': u''eaf6baf8-fc3d-456b-b17d-e8219ccef1b1''}
files
también pueden ser una lista de tuplas de dos valores, si necesita ordenar y / o múltiples campos con el mismo nombre:
requests.post(''http://requestb.in/xucj9exu'', files=((''foo'', ''bar''), (''spam'', ''eggs'')))
Si especifica files
y data
, depende del valor de los data
que se usarán para crear el cuerpo POST. Si los data
son una cadena, solo se usará; de lo contrario files
se utilizan tanto los data
como los files
, con los elementos en los data
primero.
Debe usar el atributo de name
del archivo de carga que está en el HTML del sitio. Ejemplo:
autocomplete="off" name="image">
¿Ves name="image">
? Puede encontrarlo en el HTML de un sitio para cargar el archivo. Debe usarlo para cargar el archivo con Multipart/form-data
guión:
import requests
site = ''https://prnt.sc/upload.php'' # the site where you upload the file
filename = ''image.jpg'' # name example
Aquí, en el lugar de la imagen, agregue el nombre del archivo de carga en HTML
up = {''image'':(filename, open(filename, ''rb''), "multipart/form-data")}
Si la carga requiere hacer clic en el botón para cargarla, puede usarla así:
data = {
"Button" : "Submit",
}
Entonces comienza la solicitud
request = requests.post(site, files=up, data=data)
Y hecho, archivo cargado con éxito
Debe usar el parámetro de files
para enviar una solicitud POST de formulario multiparte incluso cuando no necesite cargar ningún archivo.
Desde la fuente original de requests :
def request(method, url, **kwargs):
"""Constructs and sends a :class:`Request <Request>`.
...
:param files: (optional) Dictionary of ``''name'': file-like-objects``
(or ``{''name'': file-tuple}``) for multipart encoding upload.
``file-tuple`` can be a 2-tuple ``(''filename'', fileobj)``,
3-tuple ``(''filename'', fileobj, ''content_type'')``
or a 4-tuple ``(''filename'', fileobj, ''content_type'', custom_headers)``,
where ``''content-type''`` is a string
defining the content type of the given file
and ``custom_headers`` a dict-like object
containing additional headers to add for the file.
La parte relevante es: file-tuple can be a
2-tuple
, 3-tuple
or a
4-tuple
.
En función de lo anterior, la solicitud de formulario multiparte más simple que incluye ambos archivos para cargar y campos de formulario se verá así:
multipart_form_data = {
''file2'': (''custom_file_name.zip'', open(''myfile.zip'', ''rb'')),
''action'': ('''', ''store''),
''path'': ('''', ''/path1'')
}
response = requests.post(''https://httpbin.org/post'', files=multipart_form_data)
print(response.content)
☝ Observe la cadena vacía como primer argumento en la tupla para campos de texto plano: es un marcador de posición para el campo de nombre de archivo que solo se usa para cargar archivos, pero para los campos de texto todavía se requiere el marcador de posición vacío para enviar los datos .
Si esta API no es suficientemente pitónica para usted o si necesita publicar varios campos con el mismo nombre, considere usar las solicitudes toolbelt (pip install requests_toolbelt
) que es una extensión del módulo de solicitudes principales que brinda soporte para la transmisión de carga de archivos como así como MultipartEncoder que puede usarse en lugar de files
y que acepta parámetros tanto en diccionarios como en tuplas. MultipartEncoder
se puede usar tanto para solicitudes de varias partes con o sin campos de carga reales. Debe asignarse al parámetro de data
.
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
multipart_data = MultipartEncoder(
fields={
# a file upload field
''file'': (''file.py'', open(''file.zip'', ''rb''), ''text/plain'')
# plain text fields
''field0'': ''value0'',
''field1'': ''value1'',
}
)
response = requests.post(''http://httpbin.org/post'', data=multipart_data,
headers={''Content-Type'': multipart_data.content_type})
Si necesita enviar varios campos con el mismo nombre, o si el orden de los campos del formulario es importante, se puede usar una tupla o una lista en lugar de un diccionario, es decir:
multipart_data = MultipartEncoder(
fields=(
(''action'', ''ingest''),
(''item'', ''spam''),
(''item'', ''sausage''),
(''item'', ''eggs''),
)
)
Desde que se escribieron las respuestas anteriores, las solicitudes han cambiado. Eche un vistazo al this para más detalles y este comentario para un ejemplo.
En resumen, el parámetro de archivos toma un dict
con la clave que es el nombre del campo de formulario y el valor que es una cadena o una tupla de 2, 3 o 4 longitudes, como se describe en la sección POST un Archivo codificado en varias partes en el solicita inicio rápido:
>>> url = ''http://httpbin.org/post''
>>> files = {''file'': (''report.xls'', open(''report.xls'', ''rb''), ''application/vnd.ms-excel'', {''Expires'': ''0''})}
En lo anterior, la tupla se compone de la siguiente manera:
(filename, data, content_type, headers)
Si el valor es solo una cadena, el nombre del archivo será el mismo que el de la clave, como se muestra a continuación:
>>> files = {''obvius_session_id'': ''72c2b6f406cdabd578c5fd7598557c52''}
Content-Disposition: form-data; name="obvius_session_id"; filename="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52
Si el valor es una tupla y la primera entrada es None
la propiedad del nombre de archivo no se incluirá:
>>> files = {''obvius_session_id'': (None, ''72c2b6f406cdabd578c5fd7598557c52'')}
Content-Disposition: form-data; name="obvius_session_id"
Content-Type: application/octet-stream
72c2b6f406cdabd578c5fd7598557c52