使用Python的HTTP POST二进制文件:简洁的非pycurl示例?

时间:2009-08-12 05:07:58

标签: python http post binary

我有兴趣编写一个简短的python脚本,通过POST请求将短二进制文件(.wav / .raw音频)上传到远程服务器。

我用pycurl完成了这个,这使得它非常简单并且产生了一个简洁的脚本;不幸的是,它还要求结束 用户安装了pycurl,我不能依赖它。

我也看过其他帖子中的一些例子,这些例子只依赖于基本库,urllib,urllib2等,但是这些通常看起来相当冗长,这也是我想要避免的。

我想知道是否有任何简洁的例子不需要使用外部库,第三方可以快速轻松地理解 - 即使他们不熟悉python。

我目前使用的是什么,


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

这不完全正确,但它给了你一般的想法。它很好用,第三方很容易理解,它需要pycurl。

5 个答案:

答案 0 :(得分:4)

发布文件需要multipart/form-data编码,据我所知,使用stdlib执行此操作并不简单(即单行或其他)。但正如你所提到的,那里有很多食谱。

虽然它们看起来很冗长,但是你的用例表明你可能只需将它封装到一个函数或类中,而不用担心太多,对吧?看一下ActiveState上的食谱,并阅读建议的评论:

或者看看这个PyMOTW中的MultiPartForm类,它似乎非常可重用:

我相信两者都处理二进制文件。

答案 1 :(得分:2)

我今天遇到了类似的问题,在尝试了pycurl和multipart / form-data之后,我决定阅读python httplib / urllib2源代码以找出答案,我确实得到了一个比较好的解决方案:

  1. 在发布
  2. 之前设置Content-Length标头(文件)
  3. 在发布帖子时传递打开的文件
  4. 以下是代码:

    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
    

    请参阅我的博文:http://www.2maomao.com/blog/python-http-post-a-binary-file-using-urllib2/

答案 2 :(得分:2)

我知道这是一个旧的旧堆栈,但我有一个不同的解决方案。

如果你经历了构建所有魔术标题和所有内容的麻烦,并且只是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

如果您使用HTTP://而不是HTTPS://则使用HTTPConnection替换上面的所有HTTPSConnection实例。

在人们对我不满之前,是的,这是一个糟糕的解决方案,但它是一种修复现有代码的方法,你真的不想重新设计以其他方式去做。

为什么要修复它?去看看原始的Python源代码,httplib.py文件。

答案 3 :(得分:1)

urllib如何更加冗长?除了从

开始,你基本上以同样的方式构建postdict
postdict = [ ('userfile', open(wavfile, 'rb').read()) ]

一旦你发布了postdict,

resp = urllib.urlopen(url, urllib.urlencode(postdict))

然后你得到并保存resp.read()并且可能取消引用并在需要时尝试JSON加载。看起来它实际上会更短!那我错过了什么......?

答案 4 :(得分:0)

urllib.urlencode不喜欢某种二进制数据。