¿Hay alguna manera de hacer HTTP PUT en Python?

220

Necesito subir algunos datos a un servidor usando HTTP PUTen Python. De mi breve lectura de los documentos urllib2, solo hace HTTP POST. ¿Hay alguna forma de hacer un HTTP PUTen python?

Rory
fuente

Respuestas:

311

He usado una variedad de libs HTTP de Python en el pasado, y me he decidido por ' Solicitudes ' como mi favorito. Las bibliotecas existentes tenían interfaces bastante utilizables, pero el código puede terminar siendo unas pocas líneas demasiado largas para operaciones simples. Un PUT básico en las solicitudes se ve así:

payload = {'username': 'bob', 'email': '[email protected]'}
>>> r = requests.put("http://somedomain.org/endpoint", data=payload)

Luego puede verificar el código de estado de respuesta con:

r.status_code

o la respuesta con:

r.content

Requests tiene mucho azúcar sináctico y atajos que te harán la vida más fácil.

John Carter
fuente
11
A pesar de que el código anterior parece extremadamente simple, no infiera que las 'solicitudes' de alguna manera faltan o tienen poca potencia. Es extremadamente capaz, solo que con una interfaz muy ordenada.
Jonathan Hartley
55
Me pregunto cuánto tiempo llevará esta respuesta acumular gradualmente votos hasta que se convierta en la nueva respuesta más votada.
Jonathan Hartley
2
¡No entiendes cuánto es esto increíble! ¡Estaba luchando con una biblioteca java horrible! ... ¡Creo que te quiero un poco por señalar "Solicitudes"!
Shehaaz
3
Use el json=payloadparámetro si desea que los datos estén en el cuerpo.
ManuelSchneid3r
1
Quiero señalar rápidamente que esta interfaz es mejor que la otra respuesta, porque es una programación funcional. ¿Por qué crear un objeto cuando lo hará una función con estructuras de datos simples como parámetros? Desearía que otras bibliotecas de Python hicieran lo mismo.
Marc
242
import urllib2
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request('http://example.org', data='your_put_data')
request.add_header('Content-Type', 'your/contenttype')
request.get_method = lambda: 'PUT'
url = opener.open(request)
Florian Bösch
fuente
44
Parece un poco sucio, pero parece funcionar de manera elegante y completa
Rory
66
Sería menos complicado si subclase urllib2.Request en lugar de parchearlo.
Jason R. Coombs
23
Esta respuesta fue brillante cuando fue escrita, pero hoy en día es mucho más fácil usar el paquete de 'solicitudes', ver la respuesta de John Carter. 'Solicitudes' no es en modo alguno un juguete, es extremadamente capaz.
Jonathan Hartley
55
Esta respuesta es canónica, pero anticuada. Por favor, considere usar la requestsbiblioteca en su lugar.
jsalonen
13
Gracias, no quería usar nada fuera de la biblioteca estándar de Python y esto funciona perfectamente. No entiendo bien por qué el urllib2 está diseñado para atender GET y POST de manera estándar, pero esta solución es el campeón. ¿Se puede reutilizar urllib2.build_opener (urllib2.HTTPHandler) en varias llamadas?
WeNeedAnswers
46

Httplib parece una opción más limpia.

import httplib
connection =  httplib.HTTPConnection('1.2.3.4:1234')
body_content = 'BODY CONTENT GOES HERE'
connection.request('PUT', '/url/path/to/put/to', body_content)
result = connection.getresponse()
# Now result.status and result.reason contains interesting stuff
Carretes
fuente
No use httplib si usted (o cualquiera de sus usuarios potenciales) necesita soporte de proxy. Vea este artículo para más detalles.
Jason R. Coombs
Por qué dirías eso? Su artículo establece claramente que funciona. Vea la respuesta de Rolf Wester, dice que urllib falla pero httplib funciona.
Carretes
httplib solo funciona cuando el usuario se conecta explícitamente al proxy y modifica la solicitud para incluir la URL completa en el parámetro GET. La razón por la que falló urllib fue porque http_proxy no se configuró correctamente. urllib usa httplib debajo de las escenas, pero también maneja redirecciones, servidores proxy, etc.
Jason R. Coombs
Si bien esta solución funcionaría, la que usa solicitudes es mucho más simple, elegante y, en mi opinión, mejor.
tgrosinger
1
@tgrosinger Estoy de acuerdo. Esta respuesta fue publicada antes de que existieran las solicitudes. A partir de ahora, el único caso en el que esta solución sería mejor es si solo Python Standard Library estuviera disponible. De lo contrario, también recomendaría usar solicitudes.
Carretes
8

Deberías echar un vistazo al módulo httplib . Debería permitirle realizar cualquier tipo de solicitud HTTP que desee.

John Montgomery
fuente
Buena solución, pitón silencioso pero un poco demasiado cerca del metal y ya implica escribir muchos otros códigos
Rory
8

Necesitaba resolver este problema hace un tiempo para poder actuar como cliente para una API RESTful. Me decidí por httplib2 porque me permitía enviar PUT y DELETE además de GET y POST. Httplib2 no es parte de la biblioteca estándar, pero puede obtenerlo fácilmente en la quesería.

Miguel
fuente
2
httplib2 es borderware abandonware. Tiene una larga lista de errores que no se corrigen a pesar de las contribuciones de la comunidad (parches). Sugiero pensar dos veces antes de usar httplib2 en cualquier entorno de producción.
Jason R. Coombs
8

Puede usar la biblioteca de solicitudes, simplifica mucho las cosas en comparación con el enfoque urllib2. Primero instálalo desde pip:

pip install requests

Más información sobre la instalación de solicitudes .

Luego configure la solicitud de venta:

import requests
import json
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}

# Create your header as required
headers = {"content-type": "application/json", "Authorization": "<auth-key>" }

r = requests.put(url, data=json.dumps(payload), headers=headers)

Consulte la biblioteca de inicio rápido para solicitudes . Creo que esto es mucho más simple que urllib2 pero requiere la instalación e importación de este paquete adicional.

radtek
fuente
¿Las solicitudes de soporte no son PUT también?
Jeef
las solicitudes admiten obtener, colocar, publicar, eliminar encabezados y opciones. Se corrigió el ejemplo para usar put. Consulte las solicitudes de inicio rápido.
radtek
@RPradeep Gracias por eso.
radtek
8

Esto se mejoró en python3 y se documentó en la documentación de stdlib

La urllib.request.Requestclase ganó un method=...parámetro en python3.

Algunos ejemplos de uso:

req = urllib.request.Request('https://example.com/', data=b'DATA!', method='PUT')
urllib.request.urlopen(req)
Anthony Sottile
fuente
6

También recomiendo httplib2 de Joe Gregario. Utilizo esto regularmente en lugar de httplib en la lib estándar.

Corey Goldberg
fuente
3

¿Has echado un vistazo a put.py ? Lo he usado en el pasado. También puede hackear su propia solicitud con urllib.

William Keller
fuente
Realmente no quiero usar una biblioteca http de chicos al azar
Rory
tratando de importar poner obtener # pip instalar poner Descargar / desempacar poner No se pudo encontrar ninguna descarga que satisfaga el requisito poner Limpiar ... No se encontraron distribuciones para poner
Ashish Karpe
# tail -f /root/.pip/pip.log Traceback (última llamada más reciente): Archivo "/usr/lib/python2.7/dist-packages/pip/basecommand.py", línea 122, en estado principal = self.run (opciones, args) Archivo "/usr/lib/python2.7/dist-packages/pip/commands/install.py", línea 278, en ejecución require_set.prepare_files (buscador, force_root_egg_info = self.bundle, paquete = self.bundle) Archivo "/usr/lib/python2.7/dist-packages/pip/req.py", línea 1178, en prepare_files
Ashish Karpe
url = finder.find_requirement (req_to_install, upgrade = self.upgrade) Archivo "/usr/lib/python2.7/dist-packages/pip/index.py", línea 277, en find_requirement raise DistributionNotFound ('No se encontraron distribuciones en absoluto for% s '% req) DistributionNotFound: No se encontraron distribuciones para put
Ashish Karpe
2

Por supuesto, puede crear las suyas propias con las bibliotecas estándar existentes en cualquier nivel, desde sockets hasta ajustar urllib.

http://pycurl.sourceforge.net/

"PyCurl es una interfaz de Python para libcurl".

"libcurl es una biblioteca de transferencia de URL del lado del cliente gratuita y fácil de usar, ... soporta ... HTTP PUT"

"El principal inconveniente con PycURL es que es una capa delgada relativa sobre libcurl sin ninguna de esas agradables jerarquías de clase Pythonic. Esto significa que tiene una curva de aprendizaje algo pronunciada a menos que ya estés familiarizado con la API C de libcurl".

wnoise
fuente
Estoy seguro de que funcionaría, pero quiero algo un poco más pitónico
Rory
2

Si desea permanecer dentro de la biblioteca estándar, puede subclasificar urllib2.Request:

import urllib2

class RequestWithMethod(urllib2.Request):
    def __init__(self, *args, **kwargs):
        self._method = kwargs.pop('method', None)
        urllib2.Request.__init__(self, *args, **kwargs)

    def get_method(self):
        return self._method if self._method else super(RequestWithMethod, self).get_method()


def put_request(url, data):
    opener = urllib2.build_opener(urllib2.HTTPHandler)
    request = RequestWithMethod(url, method='PUT', data=data)
    return opener.open(request)
Wilfred Hughes
fuente
0

Una forma más adecuada de hacer esto requestssería:

import requests

payload = {'username': 'bob', 'email': '[email protected]'}

try:
    response = requests.put(url="http://somedomain.org/endpoint", data=payload)
    response.raise_for_status()
except requests.exceptions.RequestException as e:
    print(e)
    raise

Esto genera una excepción si hay un error en la solicitud HTTP PUT.

Adam Erickson
fuente