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

2024-05-13 00:10:03 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我已经用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。


Tags: thetokeyself脚本returndefcontents
3条回答

发布一个文件需要multipart/form-data编码,据我所知,用stdlib做这件事(即一行代码或其他东西)并不容易。但正如你提到的,有很多食谱。

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

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

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

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

如果您在构建所有magic头和所有内容时遇到了麻烦,只是因为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文件。

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

  1. 在进行post之前设置(文件的)内容长度头
  2. 进行post时传递打开的文件

代码如下:

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/

相关问题 更多 >