Esiste un modo per eseguire HTTP PUT in Python


220

Devo caricare alcuni dati su un server usando HTTP PUTin Python. Dalla mia breve lettura dei documenti di urllib2, fa solo HTTP POST. C'è un modo per fare un HTTP PUTin Python?

Risposte:


311

Ho usato una varietà di librerie HTTP Python in passato e ho scelto " Richieste " come preferito. Le librerie esistenti avevano interfacce piuttosto utilizzabili, ma il codice può finire per essere troppo lungo per alcune semplici operazioni. Un PUT di base nelle richieste è simile a:

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

È quindi possibile controllare il codice dello stato della risposta con:

r.status_code

o la risposta con:

r.content

Requests ha molti zuccheri sintattici e scorciatoie che ti semplificheranno la vita.


11
Anche se il codice sopra sembra estremamente semplice, non dedurre che le "richieste" siano in qualche modo carenti o insufficienti. È estremamente capace, solo con un'interfaccia molto ordinata.
Jonathan Hartley,

5
Mi chiedo quanto tempo impiegherà questa risposta per accumulare gradualmente voti fino a quando non diventerà la nuova risposta più votata?
Jonathan Hartley,

2
Non capisci quanto sia fantastico !!! Stavo lottando con una libreria java scadente! ... Penso di amarti per aver indicato "Richieste"!
Shehaaz,

3
Utilizzare il json=payloadparametro se si desidera che i dati siano nel corpo.
ManuelSchneid3r

1
Voglio sottolineare rapidamente che questa interfaccia è migliore dell'altra risposta, perché è una programmazione funzionale. Perché creare un oggetto quando farà una funzione con semplici strutture dati come parametri. Vorrei che altre librerie di Python seguissero l'esempio.
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)

4
Sembra un po 'un trucco sporco, ma sembra funzionare in modo elegante e completo
Rory,

6
Sarebbe meno un hack se dovessi sottoclassare urllib2. Richiedi invece di rattoppare le scimmie.
Jason R. Coombs,

23
Questa risposta è stata geniale quando è stata scritta, ma al giorno d'oggi è molto più semplice utilizzare il pacchetto "richieste", vedi la risposta di John Carter. "Richieste" non è in alcun modo un giocattolo - è estremamente capace.
Jonathan Hartley,

5
Questa risposta è canonica, ma obsoleta. Per favore, considera requestsinvece l' uso della libreria.
jsalonen,

13
Grazie, non volevo usare nulla al di fuori della libreria standard di Python e questo funziona perfettamente. Non capisco bene perché urllib2 sia progettato per soddisfare GET e POST solo come standard, ma questo lavoro è campione. Urllib2.build_opener (urllib2.HTTPHandler) può essere riutilizzato in più chiamate?
WeNeedRisposte

46

Httplib sembra una scelta più pulita.

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

Non utilizzare httplib se tu (o uno qualsiasi dei tuoi potenziali utenti) hai bisogno del supporto proxy. Vedi questo articolo per i dettagli.
Jason R. Coombs,

Perché vorresti dirlo? Il tuo articolo afferma chiaramente che funziona. Vedi la risposta di Rolf Wester, dice che urllib fallisce ma httplib funziona.
Bobine

httplib funziona solo quando l'utente si collega esplicitamente al proxy e modifica la richiesta per includere l'URL completo nel parametro GET. Il motivo per cui urllib è fallito è perché http_proxy non è stato impostato correttamente. urllib usa httplib sotto le scene, ma gestisce anche reindirizzamenti, proxy, ecc.
Jason R. Coombs,

Mentre questa soluzione funzionerebbe, quella che utilizza le richieste è molto più semplice, elegante e, a mio avviso, migliore.
tgrosinger,

1
@tgrosinger Sono d'accordo. Questa risposta è stata pubblicata prima dell'esistenza delle richieste. A partire da ora, l'unico caso in cui questa soluzione sarebbe migliore è se solo la libreria standard di Python fosse disponibile. Altrimenti, consiglierei anche di usare le richieste.
Bobine il

8

Dovresti dare un'occhiata al modulo httplib . Dovrebbe consentire di effettuare qualsiasi tipo di richiesta HTTP desiderata.


Bella soluzione, silenziosa pitone ma un po 'troppo vicina al metal e che comporta già la scrittura di molti altri codici
Rory

8

Un po 'di tempo fa dovevo risolvere questo problema in modo da poter agire come client per un'API RESTful. Ho optato per httplib2 perché mi ha permesso di inviare PUT e DELETE oltre a GET e POST. Httplib2 non fa parte della libreria standard ma puoi facilmente ottenerlo dal negozio di formaggi.


2
httplib2 èandonware borderline. Ha una lunga lista di bug che non vengono risolti nonostante i contributi della community (patch). Suggerisco di pensarci due volte prima di utilizzare httplib2 in qualsiasi ambiente di produzione.
Jason R. Coombs,

8

Puoi usare la libreria delle richieste, semplifica molto le cose rispetto all'approccio urllib2. Prima installalo dal pip:

pip install requests

Ulteriori informazioni sull'installazione di richieste .

Quindi impostare la richiesta put:

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)

Vedi la libreria di avvio rapido per le richieste . Penso che sia molto più semplice di urllib2 ma richiede l'installazione e l'importazione di questo pacchetto aggiuntivo.


Anche le richieste non supportano PUT?
Jeef,

richieste supporta get, put, post, delete head e opzioni. Risolto l'esempio per usare put. Controlla le richieste di avvio rapido.
Radtek,

@RPradeep Grazie per quello.
Radtek,

8

Ciò è stato migliorato in python3 e documentato nella documentazione di stdlib

La urllib.request.Requestclasse ha ottenuto un method=...parametro in python3.

Alcuni esempi di utilizzo:

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


3

Hai dato un'occhiata a put.py ? L'ho usato in passato. Puoi anche hackerare la tua richiesta con urllib.


Non voglio davvero usare qualche libreria http per ragazzi casuali
Rory,

cercando import put ottenendo # pip install put Download / decompressione put Impossibile trovare download che soddisfino il requisito put Pulizia ... Nessuna distribuzione trovata per put
Ashish Karpe,

# tail -f /root/.pip/pip.log Traceback (ultima chiamata più recente): file "/usr/lib/python2.7/dist-packages/pip/basecommand.py", riga 122, nello stato principale = self.run (options, args) File "/usr/lib/python2.7/dist-packages/pip/commands/install.py", riga 278, in esecuzione requ_set.prepare_files (finder, force_root_egg_info = self.bundle, bundle = self.bundle) File "/usr/lib/python2.7/dist-packages/pip/req.py", riga 1178, in prepar_files
Ashish Karpe,

url = finder.find_requirement (req_to_install, upgrade = self.upgrade) File "/usr/lib/python2.7/dist-packages/pip/index.py", linea 277, in find_requirement raise DistributionNotFound ('Nessuna distribuzione trovata per% s '% req) DistributionNotFound: nessuna distribuzione trovata per put
Ashish Karpe

2

Ovviamente è possibile creare il proprio con le librerie standard esistenti a qualsiasi livello, dai socket fino all'ottimizzazione dell'URLlib.

http://pycurl.sourceforge.net/

"PyCurl è un'interfaccia Python per libcurl."

"libcurl è una libreria di trasferimento URL lato client gratuita e facile da usare, ... supporta ... HTTP PUT"

"Lo svantaggio principale di PycURL è che si tratta di uno strato relativamente sottile rispetto a libcurl senza nessuna di quelle belle gerarchie di classi Pythonic. Ciò significa che ha una curva di apprendimento piuttosto ripida a meno che tu non abbia già familiarità con l'API C di libcurl."


Sono sicuro che funzionerebbe, ma voglio qualcosa di un po 'più pitonico
Rory,

2

Se vuoi rimanere nella libreria standard, puoi sottoclassare 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)

0

Un modo più appropriato di farlo con requestssarebbe:

import requests

payload = {'username': 'bob', 'email': 'bob@bob.com'}

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

Ciò solleva un'eccezione se si verifica un errore nella richiesta PUT HTTP.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.