Existe alguma maneira de fazer HTTP PUT em python

220

Preciso fazer upload de alguns dados para um servidor usando HTTP PUTem python. Da minha breve leitura dos documentos urllib2, ele faz apenas HTTP POST. Existe alguma maneira de fazer um HTTP PUTem python?

Rory
fonte

Respostas:

311

Eu usei uma variedade de bibliotecas HTTP python no passado e decidi por ' Solicitações ' como a minha favorita. As bibliotecas existentes tinham interfaces bastante úteis, mas o código pode acabar sendo algumas linhas muito longas para operações simples. Um PUT básico em solicitações é semelhante a:

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

Você pode verificar o código de status da resposta com:

r.status_code

ou a resposta com:

r.content

Os pedidos têm muito açúcar sinático e atalhos que facilitarão sua vida.

John Carter
fonte
11
Mesmo que o código acima pareça extremamente simples, não deduza que as 'solicitações' estejam de alguma forma ausentes ou com pouca energia. É extremamente capaz, apenas com uma interface altamente organizada.
Jonathan Hartley
5
Gostaria de saber quanto tempo levará esta resposta para gradualmente acumular votos até que ela se torne a nova resposta mais votada?
9788 Jonathan Hartley
2
Você não entende o quanto isso é incrível !!! Eu estava lutando com uma biblioteca java crummy! ... Eu acho que meio que te amo por apontar para "Pedidos"!
Shehaaz
3
Use o json=payloadparâmetro se desejar que os dados estejam no corpo.
ManuelSchneid3r
1
Quero salientar rapidamente que essa interface é melhor que a outra resposta, porque é uma programação funcional. Por que criar um objeto quando uma função com estruturas de dados simples, como parâmetros, fará? Eu gostaria que outras bibliotecas python seguissem o exemplo.
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
fonte
4
Parece um pouco de um truque sujo, mas parece funcionar de forma elegante e completamente
Rory
6
Seria menos invasivo se você subclasse urllib2.Request, em vez de corrigi-lo.
Jason R. Coombs
23
Essa resposta foi brilhante quando foi escrita, mas hoje em dia é muito mais fácil usar o pacote 'orders', veja a resposta de John Carter. 'Pedidos' não é de forma alguma um brinquedo - é extremamente capaz.
Jonathan Hartley
5
Esta resposta é canônica, mas desatualizada. Por favor, considere usar a requestsbiblioteca.
jsalonen
13
Obrigado, eu não queria usar nada fora da biblioteca python padrão e isso funciona perfeitamente. Não entendo muito bem por que o urllib2 foi projetado para atender apenas o GET e o POST como padrão, mas essa solução é a melhor. O urllib2.build_opener (urllib2.HTTPHandler) pode ser reutilizado em várias chamadas?
WeNeedAnswers
46

Httplib parece ser uma escolha mais limpa.

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
Spooles
fonte
Não use o enableplib se você (ou qualquer um de seus usuários em potencial) precisar de suporte por proxy. Veja este artigo para detalhes.
Jason R. Coombs
Por que você diria isso? Seu artigo afirma claramente que funciona. Veja a resposta de Rolf Wester, ele diz que o urllib falha, mas o updplib funciona.
Spooles
httplib só funciona quando o usuário se conecta explicitamente ao proxy e modifica a solicitação para incluir a URL completa no parâmetro GET. A razão pela qual o urllib falhou foi porque o http_proxy não foi configurado corretamente. urllib usa httplib sob as cenas, mas também lida com redirecionamentos, proxies, etc.
Jason R. Coombs
Embora essa solução funcione, quem usa solicitações é muito mais simples, elegante e, na minha opinião, melhor.
tgrosinger
1
@tgrosinger eu concordo. Esta resposta foi publicada antes da existência de solicitações. A partir de agora, o único caso em que essa solução seria melhor seria se apenas a Biblioteca Padrão do Python estivesse disponível. Caso contrário, eu também recomendo usar solicitações.
Spooles
8

Você deve dar uma olhada no módulo httplib . Deve permitir que você faça o tipo de solicitação HTTP que desejar.

John Montgomery
fonte
Solução agradável, pythônico tranquila, mas um pouco perto demais do metal e envolvendo escrevendo um monte de outro código já
Rory
8

Eu precisava resolver esse problema também há um tempo, para poder atuar como cliente de uma API RESTful. Eu decidi pelo httplib2 porque ele me permitiu enviar PUT e DELETE, além de GET e POST. O Httplib2 não faz parte da biblioteca padrão, mas você pode facilmente obtê-lo na loja de queijos.

Mike
fonte
2
httplib2 é um abandonware borderline. Ele tem uma longa lista de bugs que não são corrigidos, apesar das contribuições da comunidade (patches). Sugiro pensar duas vezes antes de usar o Activplib2 em qualquer ambiente de produção.
Jason R. Coombs
8

Você pode usar a biblioteca de solicitações, pois simplifica bastante as coisas em comparação com a abordagem do urllib2. Primeiro instale-o a partir do pip:

pip install requests

Mais sobre a instalação de solicitações .

Em seguida, configure a solicitação de venda:

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)

Veja o início rápido para a biblioteca de solicitações . Eu acho que isso é muito mais simples que o urllib2, mas exige que este pacote adicional seja instalado e importado.

Radtek
fonte
As solicitações não suportam PUT também?
Jeef
pedidos suporta obter, colocar, postar, excluir cabeçalho e opções. Corrigido o exemplo para usar put. Confira as solicitações de início rápido.
Radtek 29/09/14
@RPradeep Obrigado por isso.
Radtek 22/02
8

Isso foi aprimorado no python3 e documentado na documentação do stdlib

A urllib.request.Requestclasse ganhou um method=...parâmetro em python3.

Alguns exemplos de uso:

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

Eu também recomendo o enableplib2 de Joe Gregario. Eu uso isso regularmente, em vez de httplib na lib padrão.

Corey Goldberg
fonte
3

Você já deu uma olhada no put.py ? Eu usei isso no passado. Você também pode hackear sua própria solicitação com urllib.

William Keller
fonte
Eu realmente não quero usar alguns caras aleatórios http biblioteca
Rory
tentando importar colocar recebendo # pip install colocar Baixando / descompactando put Não foi possível encontrar nenhum download que atenda ao requisito put Limpando ... Nenhuma distribuição encontrada para put #
Ashish Karpe
# tail -f /root/.pip/pip.log Traceback (última chamada mais recente): arquivo "/usr/lib/python2.7/dist-packages/pip/basecommand.py", linha 122, no status principal = self.run (opções, args) O arquivo "/usr/lib/python2.7/dist-packages/pip/commands/install.py", linha 278, na execução requisito_set.prepare_files (localizador, force_root_egg_info = self.bundle, bundle = self.bundle) Arquivo "/usr/lib/python2.7/dist-packages/pip/req.py", linha 1178, em prepare_files
Ashish Karpe
url = finder.find_requirement (req_to_install, upgrade = self.upgrade) Arquivo "/usr/lib/python2.7/dist-packages/pip/index.py", linha 277, em find_requirement raise DistributionNotFound ('Nenhuma distribuição encontrada para% s '% req) DistributionNotFound: Nenhuma distribuição encontrada para put
Ashish Karpe
2

É claro que você pode criar suas próprias bibliotecas padrão existentes em qualquer nível, desde soquetes até ajustes de urllib.

http://pycurl.sourceforge.net/

"PyCurl é uma interface Python para libcurl."

"libcurl é uma biblioteca de transferência de URLs gratuita e fácil de usar no lado do cliente, ... suporta ... HTTP PUT"

"A principal desvantagem do PycURL é que é uma camada relativamente fina sobre a libcurl sem nenhuma dessas hierarquias de classe Pythonic. Isso significa que ela tem uma curva de aprendizado um tanto íngreme, a menos que você já esteja familiarizado com a API C da libcurl."

wnoise
fonte
Tenho certeza de que ele iria trabalhar, mas eu quero algo um pouco mais Python
Rory
2

Se você deseja permanecer na biblioteca padrão, pode subclassificar 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
fonte
0

Uma maneira mais adequada de fazer isso requestsseria:

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

Isso gera uma exceção se houver um erro na solicitação HTTP PUT.

Adam Erickson
fonte