使用python请求生成多部分表单数据

时间:2013-10-24 22:40:26

标签: python

我一直在使用SpiderOak的这个Zipstream模块,它基本上允许你流式传输和压缩文件或文件夹而无需向光盘写任何东西。它产生大量不规则大小的数据。

现在,我正在尝试将目录上传到文件托管网站,要求我在帖子请求中发送fileapikey字段。有了请求,我必须像这样为apikey构建一个dict:

data = {'apikey': 'myapikey'}

并将整个zipstream读入字符串并将其传递给文件编码字典:

files = {'file': ('mydir.zip', the_string_that_is_a_zipped_dir)}

然后发出请求

r = requests.post(url, data=data, files=files).

这没关系。但是我希望将来传输更大的东西,并且在内存中读取整个文件是一个不错的想法。 我在请求高级部分看到你可以发送一个生成器作为数据字段,但后来我无法发送api密钥并且必须手动修改标头以设置内容类型和所有这些东西,所以它不起作用。还试图从api键和zip文件生成器中形成一个字典,就像这样 data = {   'file':('mydir.zip',generator()),   'apikey':'myapikey' }

但是失败了(正如预期的那样)。

有没有办法破解请求使用生成器为多部分表单数据中的文件生成字符串?

1 个答案:

答案 0 :(得分:0)

好的,经过一番努力,我设法让这个工作没有请求,而是使用模块poster

首先我在zipstream周围创建了一个fileobject包装器,如下所示:

from zipstream import ZipStream

class Zipit:
  def __init__( self, path):
    self.it = iter(ZipStream(path,compression=0))
    self.next_chunk = ""
    self.length = -1
    self.path = path
    self.__is_zipit__=''    
  @property
  def size(self):
    if self.length < 0:
      self.length = 0
      zip_object = ZipStream(self.path,compression=0)
      for data in zip_object:
        self.length += len(data)
    return self.length

  def growChunk( self ):
    self.next_chunk = self.next_chunk + self.it.next()
  def read( self, n ):
    if self.next_chunk == None:
      return None
    try:
      while len(self.next_chunk)<n:
        self.growChunk()
      rv = self.next_chunk[:n]
      self.next_chunk = self.next_chunk[n:]
      return rv
    except StopIteration:
      rv = self.next_chunk
      self.next_chunk = None
      return rv

为了拥有一个简单的api(代码无耻地改编自SO上的另一个例子)。

然后根据海报的doc创建必要的多部分对象:

z = Zipit('/my/path/to/zip')

f = MultipartParam('file', fileobj=z, filesize=z.size, filename='test.zip',filetype='application/zip')
datagen, headers = multipart_encode([ f, ('akey', 'mykey')])

如果fileobject字段是Zipit实例,最后一个hack就是跳过重置:

   def reset(self):
        if hasattr(self.fileobj, '__is_zipit__'): return
        if self.fileobj is not None:
            self.fileobj.seek(0)
        elif self.value is None:
            raise ValueError("Don't know how to reset this parameter")

这对我有用。希望它能帮助你们五个人中的任何一个。