代码之家  ›  专栏  ›  技术社区  ›  si28719e

使用python的HTTPPOST二进制文件:简明的非pycurl示例?

  •  5
  • si28719e  · 技术社区  · 15 年前

    我对编写一个简短的python脚本很感兴趣,它通过POST请求将一个简短的二进制文件(.wav/.raw audio)上载到远程服务器。

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

    我在其他文章中也看到了一些只依赖基本库、urllib、urlib2等的例子,但是这些通常看起来很冗长,这也是我想避免的。

    我想知道是否有一些简洁的例子不需要使用外部库,并且第三方能够快速、轻松地理解这些例子——即使他们对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
    

    这不准确,但它给了你一个大概的想法。它工作得很好,第三方很容易理解, 但是 它需要小卷发。

    5 回复  |  直到 10 年前
        1
  •  4
  •   twasbrillig    10 年前

    发布文件需要 multipart/form-data 而且,据我所知,用stdlib进行编码并不是一种简单的方法(即一个线性函数或其他东西)。但是正如你提到的,有很多食谱。

    尽管它们看起来很冗长,但您的用例建议您可以将其封装到一个函数或类中,而不用太担心,对吗?查看ActiveState上的配方并阅读评论以获取建议:

    或者看到 MultiPartForm 在这个pymotw中的类,它看起来非常可重用:

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

        2
  •  2
  •   user935714    13 年前

    今天我遇到了类似的问题,在尝试了pycurl和multipart/form数据之后,我决定读取python httplib/urllib2源代码来找出答案,我得到了一个相当好的解决方案:

    1. 在发布前设置内容长度头(文件的头)
    2. 发布时传递打开的文件

    代码如下:

    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/

        3
  •  2
  •   tara    12 年前

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

    如果您遇到了构建所有魔法头和所有东西的麻烦,并且对突然间一个二进制文件不能通过感到不安,因为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://,则将上面的httpsConnection的所有实例替换为httpConnection。

    在人们对我感到不安之前,是的,这是一个糟糕的解决方案,但这是一种修复现有代码的方法,你真的不想用其他方法重新设计。

    为什么要修复它?查看原始的python源文件httplib.py。

        4
  •  1
  •   Alex Martelli    15 年前

    乌里布怎么会更详细呢?您构建postdict的方式基本相同,除了从

    postdict = [ ('userfile', open(wavfile, 'rb').read()) ]
    

    一旦你写了博士后,

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

    然后你得到并保存 resp.read() 如果需要的话,可以取消引用并尝试JSON加载。看起来要短一点!那么我错过了什么…?

        5
  •  0
  •   Leo    14 年前

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