Existe-t-il un moyen de faire HTTP PUT en python

220

J'ai besoin de télécharger des données sur un serveur en utilisant HTTP PUTen python. D'après ma brève lecture des documents urllib2, il ne fait que HTTP POST. Existe-t-il un moyen de faire un HTTP PUTen python?

Rory
la source

Réponses:

311

J'ai utilisé une variété de bibliothèques HTTP python dans le passé, et j'ai choisi " Requêtes " comme mon préféré. Les bibliothèques existantes avaient des interfaces assez utilisables, mais le code peut finir par être trop long pour quelques opérations simples. Un PUT de base dans les requêtes ressemble à:

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

Vous pouvez ensuite vérifier le code d'état de réponse avec:

r.status_code

ou la réponse avec:

r.content

Les demandes contiennent beaucoup de sucre et de raccourcis synactiques qui vous faciliteront la vie.

John Carter
la source
11
Même si le code ci-dessus semble extrêmement simple, ne déduisez pas que les «demandes» manquent ou sont sous-alimentées. Il est extrêmement capable, juste avec une interface très soignée.
Jonathan Hartley
5
Je me demande combien de temps il faudra à cette réponse pour accumuler progressivement des votes jusqu'à ce qu'elle devienne la nouvelle réponse la plus votée?
Jonathan Hartley
2
Vous ne comprenez pas à quel point c'est génial !!! Je me débattais avec une bibliothèque java crummy! ... Je pense que je vous aime un peu pour pointer vers "Demandes"!
Shehaaz
3
Utilisez le json=payloadparamètre si vous souhaitez que les données soient dans le corps.
ManuelSchneid3r
1
Je tiens à souligner rapidement que cette interface est meilleure que l'autre réponse, car c'est une programmation fonctionnelle. Pourquoi créer un objet lorsqu'une fonction avec des structures de données simples comme paramètres fera l'affaire. Je souhaite que d'autres bibliothèques python emboîtent le pas.
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
la source
4
On dirait un peu un hack sale, mais cela semble fonctionner de manière élégante et complète
Rory
6
Ce serait moins un hack si vous deviez sous-classer urllib2.Request au lieu de le patcher avec un singe.
Jason R. Coombs
23
Cette réponse était brillante lorsqu'elle a été écrite, mais de nos jours, il est beaucoup plus facile d'utiliser à la place le paquet «requêtes», voir la réponse de John Carter. «Demandes» n'est en aucun cas un jouet - il est extrêmement capable.
Jonathan Hartley
5
Cette réponse est canonique, mais dépassée. Veuillez envisager d'utiliser la requestsbibliothèque à la place.
jsalonen
13
Merci, je ne voulais rien utiliser en dehors de la bibliothèque Python standard et cela fonctionne parfaitement. Je ne comprends pas très bien pourquoi l'urllib2 est conçu pour ne recevoir que GET et POST en standard, mais ce travail est champion. L'urllib2.build_opener (urllib2.HTTPHandler) peut-il être réutilisé dans plusieurs appels?
WeNeedAnswers
46

Httplib semble être un choix plus propre.

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
Bobines
la source
N'utilisez pas httplib si vous (ou l'un de vos utilisateurs potentiels) avez besoin d'un support proxy. Consultez cet article pour plus de détails.
Jason R. Coombs
Pourquoi dites vous cela? Votre article indique clairement que cela fonctionne. Voir la réponse de Rolf Wester, il dit que urllib échoue mais que httplib fonctionne.
Spooles
httplib ne fonctionne que lorsque l'utilisateur se connecte explicitement au proxy et modifie la demande pour inclure l'URL complète dans le paramètre GET. La raison pour laquelle urllib a échoué est que le http_proxy n'a pas été correctement configuré. urllib utilise httplib sous les scènes, mais gère également les redirections, les proxys, etc.
Jason R. Coombs
Bien que cette solution fonctionne, celle qui utilise les requêtes est beaucoup plus simple, élégante et à mon avis meilleure.
tgrosinger
1
@tgrosinger Je suis d'accord. Cette réponse a été publiée avant que les demandes n'existent. Pour l'instant, le seul cas où cette solution serait meilleure est que seule la bibliothèque standard Python soit disponible. Sinon, je recommanderais également d'utiliser les demandes.
Spooles
8

Vous devriez jeter un œil au module httplib . Il devrait vous permettre de faire la sorte de requête HTTP que vous souhaitez.

John Montgomery
la source
Belle solution, pythonique calme mais un peu trop proche du métal et impliquant déjà l'écriture de beaucoup d'autres codes
Rory
8

J'avais aussi besoin de résoudre ce problème il y a quelque temps pour pouvoir agir en tant que client pour une API RESTful. J'ai opté pour httplib2 car cela m'a permis d'envoyer PUT et DELETE en plus de GET et POST. Httplib2 ne fait pas partie de la bibliothèque standard mais vous pouvez facilement l'obtenir auprès de la fromagerie.

Mike
la source
2
httplib2 est un abandonware limite. Il a une longue liste de bogues qui ne sont pas corrigés malgré les contributions de la communauté (correctifs). Je suggère de réfléchir à deux fois avant d'utiliser httplib2 dans tous les environnements de production.
Jason R. Coombs
8

Vous pouvez utiliser la bibliothèque de requêtes, cela simplifie beaucoup les choses par rapport à l'approche urllib2. Installez-le d'abord à partir de pip:

pip install requests

Plus d'informations sur l' installation des demandes .

Ensuite, configurez la demande de vente:

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)

Voir la bibliothèque de démarrage rapide pour les demandes . Je pense que c'est beaucoup plus simple que urllib2 mais nécessite que ce package supplémentaire soit installé et importé.

radtek
la source
Les demandes ne prennent-elles pas également en charge PUT?
Jeef
demande les supports obtenir, mettre, publier, supprimer la tête et les options. Correction de l'exemple d'utilisation de put. Consultez le démarrage rapide des demandes.
radtek
@RPradeep Merci pour cela.
radtek
8

Cela a été amélioré en python3 et documenté dans la documentation stdlib

La urllib.request.Requestclasse a gagné un method=...paramètre en python3.

Quelques exemples d'utilisation:

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

Je recommande également httplib2 par Joe Gregario. Je l'utilise régulièrement au lieu de httplib dans la bibliothèque standard.

Corey Goldberg
la source
3

Avez-vous jeté un œil à put.py ? Je l'ai utilisé dans le passé. Vous pouvez également pirater votre propre demande avec urllib.

William Keller
la source
Je ne veux pas vraiment utiliser la bibliothèque http de gars aléatoires
Rory
essayer l'importation mettre obtenir # pip installer mettre Télécharger / déballer put Impossible de trouver des téléchargements qui satisfont à l'exigence mise Nettoyage ... Aucune distribution du tout trouvée pour put
Ashish Karpe
# tail -f /root/.pip/pip.log Traceback (dernier appel le plus récent): Fichier "/usr/lib/python2.7/dist-packages/pip/basecommand.py", ligne 122, dans l'état principal = self.run (options, args) Fichier "/usr/lib/python2.7/dist-packages/pip/commands/install.py", ligne 278, dans l'exécution require_set.prepare_files (finder, force_root_egg_info = self.bundle, bundle = self.bundle) Fichier "/usr/lib/python2.7/dist-packages/pip/req.py", ligne 1178, dans prepare_files
Ashish Karpe
url = finder.find_requirement (req_to_install, upgrade = self.upgrade) Fichier "/usr/lib/python2.7/dist-packages/pip/index.py", ligne 277, dans find_requirement raise DistributionNotFound ('Aucune distribution trouvée pour% s '% req) DistributionNotFound: Aucune distribution trouvée pour le put
Ashish Karpe
2

Vous pouvez bien sûr rouler les vôtres avec les bibliothèques standard existantes à n'importe quel niveau, des sockets jusqu'à peaufiner urllib.

http://pycurl.sourceforge.net/

"PyCurl est une interface Python pour libcurl."

"libcurl est une bibliothèque de transfert d'URL côté client gratuite et facile à utiliser, ... prend en charge ... HTTP PUT"

"Le principal inconvénient de PycURL est qu'il s'agit d'une couche relativement mince sur libcurl sans aucune de ces belles hiérarchies de classes Pythonic. Cela signifie qu'il a une courbe d'apprentissage quelque peu abrupte à moins que vous ne soyez déjà familier avec l'API C de libcurl."

wnoise
la source
Je suis sûr que cela fonctionnerait, mais je veux quelque chose d'un peu plus pythonique
Rory
2

Si vous souhaitez rester dans la bibliothèque standard, vous pouvez sous urllib2.Request- classer :

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
la source
0

Une façon plus appropriée de le faire requestsserait:

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

Cela déclenche une exception s'il y a une erreur dans la demande HTTP PUT.

Adam Erickson
la source