Gibt es eine Möglichkeit, HTTP-PUT in Python durchzuführen?

220

Ich muss einige Daten über HTTP PUTin Python auf einen Server hochladen . Nach meiner kurzen Lektüre der urllib2-Dokumente wird nur HTTP ausgeführt POST. Gibt es eine Möglichkeit, ein HTTP PUTin Python durchzuführen?

Rory
quelle

Antworten:

311

Ich habe in der Vergangenheit eine Vielzahl von Python-HTTP-Bibliotheken verwendet und mich für " Anfragen " als meinen Favoriten entschieden. Bestehende Bibliotheken hatten ziemlich brauchbare Schnittstellen, aber Code kann für einfache Operationen einige Zeilen zu lang sein. Ein grundlegender PUT in Anfragen sieht folgendermaßen aus:

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

Sie können den Antwortstatuscode dann überprüfen mit:

r.status_code

oder die Antwort mit:

r.content

Requests enthält viele synaktische Zucker und Verknüpfungen, die Ihnen das Leben erleichtern.

John Carter
quelle
11
Auch wenn der obige Code extrem einfach aussieht, sollten Sie nicht darauf schließen, dass "Anforderungen" in irgendeiner Weise fehlen oder unterversorgt sind. Es ist extrem leistungsfähig, nur mit einer sehr ordentlichen Oberfläche.
Jonathan Hartley
5
Ich frage mich, wie lange es dauern wird, bis diese Antwort nach und nach Stimmen sammelt, bis sie zur neuen Antwort mit den höchsten Stimmen wird.
Jonathan Hartley
2
Du verstehst nicht, wie großartig das ist !!! Ich hatte Probleme mit einer beschissenen Java-Bibliothek! ... Ich glaube, ich liebe dich irgendwie, weil du auf "Anfragen" zeigst!
Shehaaz
3
Verwenden Sie den json=payloadParameter, wenn sich die Daten im Body befinden sollen.
ManuelSchneid3r
1
Ich möchte schnell darauf hinweisen, dass diese Schnittstelle besser ist als die andere Antwort, weil es sich um funktionale Programmierung handelt. Warum ein Objekt erstellen, wenn eine Funktion mit einfachen Datenstrukturen als Parameter ausreicht? Ich wünschte, andere Python-Bibliotheken würden diesem Beispiel folgen.
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
quelle
4
Sieht aus wie ein schmutziger Hack, scheint aber elegant und vollständig zu funktionieren
Rory,
6
Es wäre weniger ein Hack, wenn Sie urllib2.Request unterordnen würden, anstatt es mit Affen zu patchen.
Jason R. Coombs
23
Diese Antwort war brillant, als sie geschrieben wurde, aber heutzutage ist es viel einfacher, stattdessen das Paket "Anfragen" zu verwenden, siehe John Carters Antwort. 'Requests' ist in keiner Weise ein Spielzeug - es ist extrem fähig.
Jonathan Hartley
5
Diese Antwort ist kanonisch, aber veraltet. Bitte erwägen Sie requestsstattdessen die Verwendung einer Bibliothek.
jsalonen
13
Vielen Dank, ich wollte nichts außerhalb der Standard-Python-Bibliothek verwenden und das funktioniert perfekt. Ich verstehe nicht ganz, warum die urllib2 standardmäßig nur für GET und POST ausgelegt ist, aber diese Problemumgehung ist ein Champion. Kann der urllib2.build_opener (urllib2.HTTPHandler) in mehreren Aufrufen wiederverwendet werden?
WeNeedAnswers
46

Httplib scheint eine sauberere Wahl zu sein.

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
Spulen
quelle
Verwenden Sie httplib nicht, wenn Sie (oder einer Ihrer potenziellen Benutzer) Proxy-Unterstützung benötigen. Weitere Informationen finden Sie in diesem Artikel .
Jason R. Coombs
Wieso würdest du so etwas sagen? Ihr Artikel besagt eindeutig, dass es funktioniert. Siehe Rolf Westers Antwort, er sagt, dass urllib fehlschlägt, aber httplib funktioniert.
Spulen
httplib funktioniert nur, wenn der Benutzer explizit eine Verbindung zum Proxy herstellt und die Anforderung so ändert, dass die vollständige URL in den Parameter GET aufgenommen wird. Der Grund, warum urllib fehlgeschlagen ist, war, dass der http_proxy nicht richtig eingestellt wurde. urllib verwendet httplib unter den Kulissen, behandelt aber auch Weiterleitungen, Proxys usw.
Jason R. Coombs
Während diese Lösung funktionieren würde, ist die mit Anfragen viel einfacher, eleganter und meiner Meinung nach besser.
Tgrosinger
1
@tgrosinger Ich stimme zu. Diese Antwort wurde veröffentlicht, bevor Anfragen vorhanden waren. Ab sofort wäre diese Lösung nur dann besser, wenn nur die Python-Standardbibliothek verfügbar wäre. Ansonsten würde ich auch empfehlen, Anfragen zu verwenden.
Spulen
8

Sie sollten sich das httplib-Modul ansehen . Sie sollten die gewünschte HTTP-Anfrage stellen können.

John Montgomery
quelle
Gute Lösung, leise pythonisch, aber etwas zu nah am Metall und mit viel anderem Code verbunden
Rory
8

Ich musste dieses Problem auch vor einiger Zeit lösen, damit ich als Client für eine RESTful-API fungieren konnte. Ich habe mich für httplib2 entschieden, weil ich damit zusätzlich zu GET und POST auch PUT und DELETE senden konnte. Httplib2 ist nicht Teil der Standardbibliothek, kann aber problemlos im Käsegeschäft bezogen werden.

Mike
quelle
2
httplib2 ist Borderline-Abbruchware. Es gibt eine lange Liste von Fehlern, die trotz Community-Beiträgen (Patches) nicht behoben werden. Ich empfehle, zweimal darüber nachzudenken, bevor Sie httplib2 in Produktionsumgebungen verwenden.
Jason R. Coombs
8

Sie können die Anforderungsbibliothek verwenden. Sie vereinfacht die Arbeit im Vergleich zum urllib2-Ansatz erheblich. Installieren Sie es zuerst von pip:

pip install requests

Weitere Informationen zum Installieren von Anforderungen .

Richten Sie dann die Put-Anfrage ein:

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)

Informationen zur Anforderungsbibliothek finden Sie im Schnellstart . Ich denke, dies ist viel einfacher als urllib2, erfordert jedoch die Installation und den Import dieses zusätzlichen Pakets.

radtek
quelle
Unterstützt Anfragen nicht auch PUT?
Jeef
Anfragen unterstützen das Abrufen, Setzen, Veröffentlichen, Löschen von Kopf und Optionen. Das Beispiel für put wurde korrigiert. Check out Anfragen Schnellstart.
Radtek
@RPradeep Danke dafür.
Radtek
8

Dies wurde in Python3 verbessert und in der stdlib-Dokumentation dokumentiert

Die urllib.request.RequestKlasse hat einen method=...Parameter in Python3 erhalten.

Einige Beispiele für die Verwendung:

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

Ich empfehle auch httplib2 von Joe Gregario. Ich benutze dies regelmäßig anstelle von httplib in der Standardbibliothek.

Corey Goldberg
quelle
3

Haben Sie sich put.py angesehen ? Ich habe es in der Vergangenheit benutzt. Sie können auch einfach Ihre eigene Anfrage mit urllib hacken.

William Keller
quelle
Ich möchte nicht wirklich einige zufällige Jungs http Bibliothek verwenden
Rory
versuchen zu importieren put bekommen # pip install put herunterladen / entpacken put konnte keine Downloads finden, die die Anforderungen erfüllen put put Aufräumen ... Es wurden überhaupt keine Distributionen für put gefunden
Ashish Karpe
# tail -f /root/.pip/pip.log Traceback (letzter Aufruf zuletzt): Datei "/usr/lib/python2.7/dist-packages/pip/basecommand.py", Zeile 122, im Hauptstatus = self.run (options, args) Datei "/usr/lib/python2.7/dist-packages/pip/commands/install.py", Zeile 278, in run require_set.prepare_files (finder, force_root_egg_info = self.bundle, bundle = self.bundle) Datei "/usr/lib/python2.7/dist-packages/pip/req.py", Zeile 1178, in prepare_files
Ashish Karpe
url = finder.find_requirement (req_to_install, upgrade = self.upgrade) Datei "/usr/lib/python2.7/dist-packages/pip/index.py", Zeile 277, in find_requirement erhöhen DistributionNotFound ('Keine Distributionen gefunden für% s '% req) DistributionNotFound: Es wurden überhaupt keine Distributionen für put gefunden
Ashish Karpe
2

Sie können natürlich Ihre eigenen mit den vorhandenen Standardbibliotheken auf jeder Ebene von Sockets bis zur Optimierung von urllib rollen.

http://pycurl.sourceforge.net/

"PyCurl ist eine Python-Schnittstelle zu libcurl."

"libcurl ist eine kostenlose und benutzerfreundliche clientseitige URL-Übertragungsbibliothek, ... unterstützt ... HTTP PUT"

"Der Hauptnachteil von PycURL ist, dass es eine relativ dünne Schicht über libcurl ohne diese netten Pythonic-Klassenhierarchien ist. Dies bedeutet, dass es eine etwas steile Lernkurve hat, es sei denn, Sie sind bereits mit der C-API von libcurl vertraut."

wnoise
quelle
Ich bin mir sicher, dass es funktionieren würde, aber ich möchte etwas Pythonischeres
Rory
2

Wenn Sie in der Standardbibliothek bleiben möchten, können Sie folgende Unterklassen erstellen 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
quelle
0

Ein geeigneterer Weg, dies zu tun, requestswäre:

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

Dies löst eine Ausnahme aus, wenn in der HTTP-PUT-Anforderung ein Fehler vorliegt.

Adam Erickson
quelle