有没有办法在Python中进行HTTP PUT请求?

230

我需要使用Python中的HTTP PUT方法将一些数据上传到服务器。从我简短阅读urllib2文档的了解,它只支持HTTP POST

是否有办法在Python中执行HTTP PUT操作?

14个回答

327

我过去使用过各种Python HTTP库,最终我选择了requests作为我的首选。现有的库具有相当可用的接口,但对于简单操作而言,代码可能会变得过长。使用requests进行基本的PUT请求如下:

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

您可以使用以下代码检查响应状态码:

r.status_code

或使用以下响应:

r.content

Requests提供了很多语法糖和快捷方式,这些可以让你的生活更加轻松。


11
尽管上述代码看起来非常简单,但不要认为 'requests' 在任何方面缺乏能力或动力。它非常强大,只是具有高度整洁的界面。 - Jonathan Hartley
5
我很想知道这个回答需要多久才能逐渐积累投票,直到成为新的最高投票答案? - Jonathan Hartley
2
你不知道这有多棒!!!我一直在苦恼一个糟糕的Java库!...我觉得我有点爱你,因为你指向了“Requests”! - Shehaaz
4
如果您希望数据在请求正文中,可以使用json=payload参数。 - ManuelSchneid3r
1
我想快速指出,这个接口比其他答案更好,因为它是函数式编程。当参数是简单数据结构时,为什么要创建一个对象呢?我希望其他Python库也能效仿。 - Marc
显示剩余5条评论

246
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)

6
如果您使用子类化urllib2.Request而不是对其进行猴子补丁,那么这将更少地显得像一个hack。 - Jason R. Coombs
23
当这篇回答被写出来时,它很棒,但现在使用“requests”包要容易得多,可以参考John Carter的回答。 “Requests”绝不是玩具 - 它非常强大。 - Jonathan Hartley
5
这个答案是规范的,但已经过时了。请考虑改用“requests”库。 - jsalonen
13
谢谢,我不想使用标准 Python 库之外的任何东西,这个方法非常完美。我不太明白为什么 urllib2 只设计了 GET 和 POST,但这个解决方法很棒。urllib2.build_opener(urllib2.HTTPHandler) 可以在多次调用中重复使用吗? - WeNeedAnswers
4
如果您不需要使用opener,可以使用urllib2.urlopen而不是opener.open - Xiao
显示剩余5条评论

47

Httplib似乎是一个更干净的选择。

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

如果您(或任何潜在用户)需要代理支持,请勿使用httplib。有关详细信息,请参见此文章:http://www.velocityreviews.com/forums/t325113-httplib-and-proxy.html。 - Jason R. Coombs
你为什么这样说?你的文章明确表示它是有效的。看看Rolf Wester的回答,他说urllib失败了但httplib可以工作。 - Spooles
仅当用户显式地连接到代理并修改请求以在GET参数中包括完整的URL时,httplib才起作用。 urllib 失败的原因是 http_proxy 没有正确设置。urllib 在幕后使用 httplib,但也处理重定向、代理等。 - Jason R. Coombs
虽然这个解决方案可以工作,但使用 requests 的解决方案更简单、优雅,而且在我看来更好。 - tgrosinger
1
@tgrosinger 我同意。这个答案是在请求存在之前发布的。现在,唯一适用此解决方案的情况是只有Python标准库可用的情况。否则,我也建议使用requests。 - Spooles

13

您可以使用requests库,与采用urllib2方法相比,它能够使许多事情变得简单。首先从pip安装它:

pip install requests

更多关于安装requests的内容。
然后设置 PUT 请求:
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)

请查看Requests库快速入门指南。相比urllib2,我认为这个库更加简单易用,但需要安装并导入额外的包。


请求库也支持PUT方法吗? - Jeef
requests支持get、put、post、delete、head和options。将示例更改为使用put。请查看requests快速入门。 - radtek
@RPradeep 谢谢你。 - radtek

10

这在Python3中得到了改进,并在标准库文档中有所记录。

urllib.request.Request类在Python 3中增加了一个method = ...参数。

一些示例用法:

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

8
你应该查看httplib模块。它可以让你发出任何类型的HTTP请求。

不错的解决方案,很符合Pythonic的风格,但是有点过于接近底层,需要编写大量其他代码。 - Amandasaurus

8

我曾经也需要解决这个问题,以便我可以作为RESTful API的客户端。最终我选择了httplib2,因为它不仅支持GET和POST请求,还支持PUT和DELETE请求。虽然httplib2不是Python标准库的一部分,但你可以很容易地从cheese shop获取它。


2
httplib2 已经接近废弃状态了。尽管社区做出了贡献(补丁),但它有一长串未修复的 bug。我建议在任何生产环境中使用 httplib2 之前三思。 - Jason R. Coombs

6

我还推荐使用Joe Gregario的httplib2。 我经常使用它来代替标准库中的httplib。


3

你看过 put.py 了吗?我之前用过它。你也可以使用 urllib 编写自己的请求。


我不想使用一些随意的人编写的HTTP库。 - Amandasaurus
尝试导入put 获取#pip install put 正在下载/解压put 未找到满足要求的任何下载内容 清理中... 没有找到任何分发put - Ashish Karpe

tail -f /root/.pip/pip.log

最新调用(Traceback): File "/usr/lib/python2.7/dist-packages/pip/basecommand.py", line 122, in main status = self.run(options, args) File "/usr/lib/python2.7/dist-packages/pip/commands/install.py", line 278, in run requirement_set.prepare_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle) File "/usr/lib/python2.7/dist-packages/pip/req.py", line 1178, in prepare_files
- Ashish Karpe
url = finder.find_requirement(req_to_install, upgrade=self.upgrade) 在"/usr/lib/python2.7/dist-packages/pip/index.py"文件的第277行,find_requirement函数中,如果找不到任何分发版本,则会引发DistributionNotFound异常,异常信息为"No distributions at all found for put"。 - Ashish Karpe

2

如果您想保持在标准库中,您可以继承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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接