【问题标题】:python requests api not posting in-memory zipped filepython请求api不发布内存压缩文件
【发布时间】:2016-02-18 19:30:41
【问题描述】:

问题:我怎样才能让它工作

我正在尝试使用 python requests api 将压缩文件发送到服务器。我在文档中看到了这种方法:

r = requests.post(url, files=open('foo.png', 'rb'))

但我所做的不同之处在于,我拥有的压缩文件在内存中,只有一个 python 对象,没有创建文件的物理压缩版本:

我正在使用 zipfile api,这就是我创建 zip 文件的方式:

inMemoryOutputFile = StringIO()
outFile = zipfile.ZipFile(inMemoryOutputFile, "w",
        compression=zipfile.ZIP_DEFLATED)

并尝试以下操作(写入 zip 文件后):

r = requests.post(url, outFile)

但是它不起作用,看起来对象没有被识别为参数。这是堆栈跟踪

Traceback (most recent call last):   File
"/Users/abdulahmad/Desktop/upload-script-ve/bin/cogs", line 11, in
<module>
    sys.exit(main())   File "/Users/abdulahmad/Desktop/upload-script-ve/lib/python2.7/site-packages/cogs/run.py",
line 396, in main
    return run(sys.argv)   File "/Users/abdulahmad/Desktop/upload-script-ve/lib/python2.7/site-packages/cogs/run.py",
line 384, in run
    return instance()   File "/Users/abdulahmad/Desktop/upload-script-ve//src/ctl.py",
line 53, in __call__
    handler = uploader(self.url, self.file)   File "/Users/abdulahmad/Desktop/upload-script-ve//src/uploader.py",
line 24, in __call__
    response = self.session.post(url, files=payload) 

#this is where I'm adding the file (the payload)

File "/Users/abdulahmad/Desktop/upload-script-ve/lib/python2.7/site-packages/requests/sessions.py",
line 511, in post
    return self.request('POST', url, data=data, json=json, **kwargs)   File
"/Users/abdulahmad/Desktop/upload-script-ve/lib/python2.7/site-packages/requests/sessions.py",
line 454, in request
    prep = self.prepare_request(req)   File "/Users/abdulahmad/Desktop/upload-script-ve/lib/python2.7/site-packages/requests/sessions.py",
line 388, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),   File "/Users/abdulahmad/Desktop/upload-script-ve/lib/python2.7/site-packages/requests/models.py",
line 296, in prepare
    self.prepare_body(data, files, json)   File "/Users/abdulahmad/Desktop/upload-script-ve/lib/python2.7/site-packages/requests/models.py",
line 447, in prepare_body
    (body, content_type) = self._encode_files(files, data)   File "/Users/abdulahmad/Desktop/upload-script-ve/lib/python2.7/site-packages/requests/models.py",
line 150, in _encode_files
    fdata = fp.read() TypeError: read() takes at least 2 arguments (1 given)

实际代码:

inMemoryOutputFile = StringIO()

    parentDir, dirToZip = os.path.split(dirPath)
    def trimPath(path):
        archivePath = path.replace(parentDir, "", 1)
        if parentDir:
            archivePath = archivePath.replace(os.path.sep, "", 1)
        if not includeDirInZip:
            archivePath = archivePath.replace(dirToZip + os.path.sep, "", 1)
        return os.path.normcase(archivePath)

    outFile = zipfile.ZipFile(inMemoryOutputFile, "w",
        compression=zipfile.ZIP_DEFLATED)

    for (archiveDirPath, dirNames, fileNames) in os.walk(dirPath):
        for fileName in fileNames:
            filePath = os.path.join(archiveDirPath, fileName)
            outFile.write(filePath, trimPath(filePath))
        if not fileNames and not dirNames:
            zipInfo = zipfile.ZipInfo(trimPath(archiveDirPath) + "/")

            outFile.writestr(zipInfo, "")
    outFile.close()
    return outFile

【问题讨论】:

  • 您是否inMemoryOutputFile.seek(0) 来回退文件?您的三个示例似乎彼此没有太大关系。你给我们一个简短的跟踪,它在你调用请求的地方停止,而不是在错误所在的地方,然后是一个完全不同的请求调用的第二个堆栈跟踪。我无法理解它。
  • 您发送的是一个空文件?
  • @tdelaney 抱歉,它的 1 个堆栈跟踪,我只是在中间添加了注释以指定我在哪里调用 post 方法。
  • @PadraicCunningham 不,我正在写入 zip 文件,但它不相关
  • @PadraicCunningham 因为请求是从当前文件指针读取的,如果不重新开始寻找,它肯定会显示为空。

标签: python python-2.7 python-requests zipfile


【解决方案1】:

您需要将StringIO 缓冲区传递给requests,而不是ZipFileZipFile.read("somefile.txt") 从存档中读取一个未压缩的文件,它不读取压缩的二进制流。 read 需要 1 个参数,这就是您收到奇怪错误消息的原因。在发布之前倒回文件,否则POST 数据将为空。

此示例向您展示了工作流程。

import zipfile
from cStringIO import StringIO
import requests
import logging

logging.basicConfig(level=logging.DEBUG)

buf = StringIO()
with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED) as zippy:
    zippy.write('somefile.txt')
buf.seek(0)

requests.post('http://localhost:8080', 
    headers = {'content-type': 'application/octet-stream'},
    data=buf)

【讨论】:

  • 它应该是files={'my_file': buf},而不是data=,但在其他方面是正确的。 docs.python-requests.org/en/master/user/quickstart/…
  • @JoshJ - 这种形式适用于多部分消息,但对单个数据块使用 data 也是正确的。来自文档“数据 –(可选)字典、字节或类似文件的对象以在请求的正文中发送。”
  • OP 使用了files=,所以我指的是他在原始示例中使用的内容。我仍然支持你。
猜你喜欢
  • 2019-12-25
  • 2017-08-31
  • 1970-01-01
  • 2015-04-23
  • 2015-12-08
  • 1970-01-01
  • 1970-01-01
  • 2020-02-09
相关资源
最近更新 更多