使用 Python 的 HTTP POST 二进制文件:简洁的非 pycurl 示例?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1264300/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HTTP POST binary files using Python: concise non-pycurl examples?
提问by si28719e
I'm interested in writing a short python script which uploads a short binary file (.wav/.raw audio) via a POST request to a remote server.
我有兴趣编写一个简短的 python 脚本,该脚本通过 POST 请求将一个简短的二进制文件 (.wav/.raw 音频) 上传到远程服务器。
I've done this with pycurl, which makes it very simple and results in a concise script; unfortunately it also requires that the end user have pycurl installed, which I can't rely on.
我已经用 pycurl 做到了这一点,这使得它变得非常简单,并产生了一个简洁的脚本;不幸的是,它还要求最终用户安装 pycurl,我不能依赖它。
I've also seen some examples in other posts which rely only on basic libraries, urllib, urllib2, etc., however these generally seem to be quite verbose, which is also something I'd like to avoid.
我还在其他帖子中看到了一些仅依赖于基本库、urllib、urllib2 等的示例,但是这些通常看起来非常冗长,这也是我想避免的。
I'm wondering if there are any concise examples which do not require the use of external libraries, and which will be quick and easy for 3rd parties to understand - even if they aren't particularly familiar with python.
我想知道是否有任何不需要使用外部库的简洁示例,并且对于 3rd 方来说,这些示例可以快速轻松地理解——即使他们不是特别熟悉 python。
What I'm using at present looks like,
我目前使用的看起来像,
def upload_wav( wavfile, url=None, **kwargs ):
"""Upload a wav file to the server, return the response."""
class responseCallback:
"""Store the server response."""
def __init__(self):
self.contents=''
def body_callback(self, buf):
self.contents = self.contents + buf
def decode( self ):
self.contents = urllib.unquote(self.contents)
try:
self.contents = simplejson.loads(self.contents)
except:
return self.contents
t = responseCallback()
c = pycurl.Curl()
c.setopt(c.POST,1)
c.setopt(c.WRITEFUNCTION, t.body_callback)
c.setopt(c.URL,url)
postdict = [
('userfile',(c.FORM_FILE,wavfile)), #wav file to post
]
#If there are extra keyword args add them to the postdict
for key in kwargs:
postdict.append( (key,kwargs[key]) )
c.setopt(c.HTTPPOST,postdict)
c.setopt(c.VERBOSE,verbose)
c.perform()
c.close()
t.decode()
return t.contents
this isn't exact, but it gives you the general idea. It works great, it's simple for 3rd parties to understand, butit requires pycurl.
这并不准确,但它为您提供了总体思路。效果很好,第 3 方很容易理解,但它需要 pycurl。
采纳答案by ars
POSTing a file requires multipart/form-data
encoding and, as far as I know, there's no easy way (i.e. one-liner or something) to do this with the stdlib. But as you mentioned, there are plenty of recipes out there.
发布文件需要multipart/form-data
编码,据我所知,使用 stdlib 没有简单的方法(即单行或其他方式)来做到这一点。但正如你提到的,那里有很多食谱。
Although they seem verbose, your use case suggests that you can probably just encapsulate it once into a function or class and not worry too much, right? Take a look at the recipe on ActiveState and read the comments for suggestions:
尽管它们看起来很冗长,但您的用例表明您可能只需将它封装一次到一个函数或类中,而不必担心太多,对吧?看看 ActiveState 上的配方并阅读评论以获取建议:
or see the MultiPartForm
class in this PyMOTW, which seems pretty reusable:
或者查看MultiPartForm
这个 PyMOTW 中的类,它看起来非常可重用:
I believe both handle binary files.
我相信两者都处理二进制文件。
回答by Realfun
I met similar issue today, after tried both and pycurl and multipart/form-data, I decide to read python httplib/urllib2 source code to find out, I did get one comparably good solution:
我今天遇到了类似的问题,在尝试了 pycurl 和 multipart/form-data 之后,我决定阅读 python httplib/urllib2 源代码以找出答案,我确实得到了一个比较好的解决方案:
- set Content-Length header(of the file) before doing post
- pass a opened file when doing post
- 在发布之前设置 Content-Length 标头(文件的)
- 发布时传递打开的文件
Here is the code:
这是代码:
import urllib2, os
image_path = "png\01.png"
url = 'http://xx.oo.com/webserviceapi/postfile/'
length = os.path.getsize(image_path)
png_data = open(image_path, "rb")
request = urllib2.Request(url, data=png_data)
request.add_header('Cache-Control', 'no-cache')
request.add_header('Content-Length', '%d' % length)
request.add_header('Content-Type', 'image/png')
res = urllib2.urlopen(request).read().strip()
return res
see my blog post: http://www.2maomao.com/blog/python-http-post-a-binary-file-using-urllib2/
看我的博文:http: //www.2maomao.com/blog/python-http-post-a-binary-file-using-urllib2/
回答by tara
I know this is an old old stack, but I have a different solution.
我知道这是一个旧的旧堆栈,但我有一个不同的解决方案。
If you went thru the trouble of building all the magic headers and everything, and are just UPSET that suddenly a binary file can't pass because python library is mean.. you can monkey patch a solution..
如果您遇到了构建所有魔术头文件和所有内容的麻烦,并且只是 UPSET 突然一个二进制文件无法通过,因为 python 库是卑鄙的......你可以修补一个解决方案..
import httplib
class HTTPSConnection(httplib.HTTPSConnection):
def _send_output(self, message_body=None):
self._buffer.extend(("",""))
msg = "\r\n".join(self._buffer)
del self._buffer[:]
self.send(msg)
if message_body is not None:
self.send(message_body)
httplib.HTTPSConnection = HTTPSConnection
If you are using HTTP:// instead of HTTPS:// then replace all instances of HTTPSConnection above with HTTPConnection.
如果您使用 HTTP:// 而不是 HTTPS://,则将上面 HTTPSConnection 的所有实例替换为 HTTPConnection。
Before people get upset with me, YES, this is a BAD SOLUTION, but it is a way to fix existing code you really don't want to re-engineer to do it some other way.
在人们对我感到不满之前,是的,这是一个糟糕的解决方案,但它是一种修复现有代码的方法,你真的不想重新设计以其他方式来做。
Why does this fix it? Go look at the original Python source, httplib.py file.
为什么要解决这个问题?去看看原始的 Python 源代码,httplib.py 文件。
回答by Alex Martelli
How's urllib substantially more verbose? You build postdict basically the same way, except you start with
urllib 如何更详细?你构建 postdict 的方式基本上是一样的,除了你从
postdict = [ ('userfile', open(wavfile, 'rb').read()) ]
Once you vave postdict,
一旦你改变了 postdict,
resp = urllib.urlopen(url, urllib.urlencode(postdict))
and then you get and save resp.read()
and maybe unquote and try JSON-loading if needed. Seems like it would be actually shorter! So what am I missing...?
然后你得到并保存resp.read()
,也许取消引用并在需要时尝试 JSON 加载。看起来它实际上会更短!所以我错过了什么......?
回答by Leo
urllib.urlencode doesn't like some kinds of binary data.
urllib.urlencode 不喜欢某些类型的二进制数据。