Czy jest jakiś sposób na wykonanie HTTP PUT w pythonie

220

Muszę przesłać niektóre dane na serwer za pomocą HTTP PUTw pythonie. Z mojej krótkiej lektury dokumentów urllib2 robi to tylko HTTP POST. Czy jest jakiś sposób na wykonanie HTTP PUTw Pythonie?

Rory
źródło

Odpowiedzi:

311

W przeszłości korzystałem z różnych bibliotek pythonowych bibliotek HTTP i zdecydowałem się na ' Requests ' jako moje ulubione. Istniejące biblioteki lib miały całkiem użyteczne interfejsy, ale kod może skończyć się o kilka wierszy za długi na proste operacje. Podstawowy PUT w żądaniach wygląda następująco:

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

Następnie możesz sprawdzić kod statusu odpowiedzi za pomocą:

r.status_code

lub odpowiedź z:

r.content

Żądania zawierają wiele synaktycznych cukrów i skrótów, które ułatwią ci życie.

John Carter
źródło
11
Mimo że powyższy kod wygląda na wyjątkowo prosty, nie należy wnioskować, że „żądaniom” w żaden sposób brakuje lub brakuje mocy. Jest niezwykle zdolny, tylko z bardzo schludnym interfejsem.
Jonathan Hartley
5
Zastanawiam się, ile czasu zajmie ta odpowiedź, aby stopniowo gromadzić głosy, aż stanie się ona nową, najlepiej głosowaną odpowiedzią?
Jonathan Hartley
2
Nie rozumiesz, ile to jest niesamowite !!! Walczyłem z kiepską biblioteką Java! ... Myślę, że trochę cię kocham za wskazanie „Prośby”!
Shehaaz,
3
Użyj json=payloadparametru, jeśli chcesz, aby dane były w ciele.
ManuelSchneid3r
1
Chcę szybko wskazać, że ten interfejs jest lepszy niż druga odpowiedź, ponieważ jest programowaniem funkcjonalnym. Po co tworzyć obiekt, gdy funkcja o prostych strukturach danych spełnia parametry. Chciałbym, żeby inne biblioteki Pythona poszły w tym samym kierunku.
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
źródło
4
Wygląda na brudny hack, ale wydaje się działać elegancko i kompletnie
Rory
6
Byłoby to mniej hack, gdybyś podklasował urllib2.Request zamiast łatania małpy.
Jason R. Coombs
23
Ta odpowiedź była genialna, kiedy została napisana, ale w dzisiejszych czasach dużo łatwiej jest użyć pakietu „prośby”, patrz odpowiedź Johna Cartera. „Żądania” nie są w żaden sposób zabawką - są niezwykle zdolne.
Jonathan Hartley
5
Ta odpowiedź jest kanoniczna, ale nieaktualna. requestsZamiast tego rozważ użycie biblioteki.
jsalonen,
13
Dziękuję, nie chciałem używać niczego poza standardową biblioteką Pythona i działa to idealnie. Nie do końca rozumiem, dlaczego urllib2 jest zaprojektowany tak, aby obsługiwać tylko GET i POST w standardzie, ale to obejście jest mistrzem. Czy urllib2.build_opener (urllib2.HTTPHandler) może być ponownie użyty w wielu połączeniach?
WeNeedAnswers
46

Httplib wydaje się czystszym wyborem.

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
Szpule
źródło
Nie używaj httplib, jeśli potrzebujesz (lub któregokolwiek z potencjalnych użytkowników) wsparcia proxy. Szczegółowe informacje można znaleźć w tym artykule .
Jason R. Coombs
Dlaczego to powiedziałeś? Twój artykuł wyraźnie stwierdza, że ​​to działa. Zobacz odpowiedź Rolfa Westera, mówi, że urllib nie działa, ale httplib działa.
Spooles,
httplib działa tylko wtedy, gdy użytkownik jawnie łączy się z serwerem proxy i modyfikuje żądanie, aby uwzględnić pełny adres URL w parametrze GET. Przyczyną niepowodzenia adresu URL urllib było nieprawidłowe ustawienie http_proxy. urllib używa httplib pod scenami, ale obsługuje również przekierowania, proxy itp.
Jason R. Coombs
Chociaż to rozwiązanie zadziałałoby, to użycie żądań jest znacznie prostsze, eleganckie i moim zdaniem lepsze.
tgrosinger
1
@tgrosinger Zgadzam się. Ta odpowiedź została opublikowana przed istnieniem żądań. Na razie jedynym rozwiązaniem, w którym to rozwiązanie byłoby lepsze, byłaby dostępna tylko standardowa biblioteka języka Python. W przeciwnym razie zalecam również korzystanie z żądań.
Spooles,
8

Powinieneś rzucić okiem na moduł httplib . Powinno to pozwolić ci na wykonanie dowolnego żądania HTTP.

John Montgomery
źródło
Ładne rozwiązanie, cichy pytoniczny, ale nieco zbyt blisko metalu i wymagające już napisania wielu innych kodów
Rory
8

Musiałem też rozwiązać ten problem jakiś czas temu, aby móc działać jako klient interfejsu API RESTful. Ustawiłem na httplib2, ponieważ pozwoliło mi to wysłać PUT i DELETE oprócz GET i POST. Httplib2 nie jest częścią standardowej biblioteki, ale można go łatwo uzyskać w sklepie z serami.

Mikrofon
źródło
2
httplib2 to oprogramowanie typu borderline. Ma długą listę błędów, które nie zostały naprawione pomimo wkładu społeczności (łatek). Sugeruję zastanowienie się dwa razy przed użyciem httplib2 w dowolnym środowisku produkcyjnym.
Jason R. Coombs
8

Możesz użyć biblioteki żądań, to znacznie upraszcza sprawę w porównaniu z podejściem urllib2. Najpierw zainstaluj z pip:

pip install requests

Więcej informacji o instalowaniu żądań .

Następnie skonfiguruj żądanie sprzedaży:

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)

Zobacz bibliotekę szybkiego startu dla żądań . Myślę, że jest to o wiele prostsze niż urllib2, ale wymaga zainstalowania i zaimportowania tego dodatkowego pakietu.

radtek
źródło
Czy żądania nie obsługują również PUT?
Jeef
żądania obsługuje pobieranie, umieszczanie, wysyłanie, usuwanie nagłówka i opcji. Naprawiono przykład użycia put. Sprawdź szybki start wniosków.
radtek
@RPradeep Dzięki za to.
radtek
8

Zostało to poprawione w Python3 i udokumentowane w dokumentacji stdlib

urllib.request.RequestKlasa zyskałmethod=... parametr w python3.

Niektóre przykładowe użycie:

req = urllib.request.Request('https://example.com/', data=b'DATA!', method='PUT')
urllib.request.urlopen(req)
Anthony Sottile
źródło
6

Polecam również httplib2 autorstwa Joe Gregario. Używam tego regularnie zamiast httplib w standardowej bibliotece.

Corey Goldberg
źródło
3

Czy rzuciłeś okiem na put.py ? Używałem tego w przeszłości. Możesz też po prostu zhakować swoją własną prośbę za pomocą urllib.

William Keller
źródło
Naprawdę nie chcę używać losowej biblioteki http facetów
Rory
próba importu put pobieranie # pip instalacja put Pobieranie / rozpakowywanie put Nie można znaleźć żadnych plików do pobrania, które spełniają wymaganie put Czyszczenie ... Brak dystrybucji dla put
Ashish Karpe
# tail -f /root/.pip/pip.log Traceback (ostatnie ostatnie połączenie): Plik „/usr/lib/python2.7/dist-packages/pip/basecommand.py”, wiersz 122, w statusie głównym = self.run (opcje, argumenty) Plik „/usr/lib/python2.7/dist-packages/pip/commands/install.py”, wiersz 278, w trakcie uruchomienia wymagany_zestaw.prepare_files (finder, force_root_egg_info = self.bundle, pakiet = self.bundle) Plik „/usr/lib/python2.7/dist-packages/pip/req.py”, wiersz 1178, w plikach przygotuj
Ashish Karpe
url = finder.find_requirement (req_to_install, upgrade = self.upgrade) Plik "/usr/lib/python2.7/dist-packages/pip/index.py", wiersz 277, w find_requ wymagany podwyższenie DistributionNotFound ('Nie znaleziono żadnych dystrybucji dla% s '% req) DistributionNotFound: Nie znaleziono żadnych dystrybucji dla put
Ashish Karpe
2

Możesz oczywiście tworzyć własne z istniejącymi standardowymi bibliotekami na dowolnym poziomie, od gniazd po ulepszanie urllib.

http://pycurl.sourceforge.net/

„PyCurl to interfejs Pythona do libcurl.”

„libcurl to darmowa i łatwa w użyciu biblioteka do przesyłania adresów URL po stronie klienta, ... obsługuje ... HTTP PUT”

„Główną wadą PycURL jest to, że jest względnie cienką warstwą w stosunku do libcurl bez żadnej z tych ładnych hierarchii klas Pythona. Oznacza to, że ma dość stromą krzywą uczenia się, chyba że znasz już interfejs API C libcurl.”

wnoise
źródło
Jestem pewien, że to zadziała, ale chcę coś nieco bardziej pytonicznego
Rory,
2

Jeśli chcesz pozostać w standardowej bibliotece, możesz podklasować 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
źródło
0

Bardziej właściwym sposobem na zrobienie tego requestsbyłoby:

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

Rodzi to wyjątek, jeśli wystąpi błąd w żądaniu HTTP PUT.

Adam Erickson
źródło