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?

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': 'bob@bob.com'}
>>> 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.


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)

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

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.


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.


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.


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)


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.


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."


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)

0

Uma maneira mais adequada de fazer isso requestsseria:

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

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.