python - 使用 Python 请求 'bridge' 文件而不加载到内存中?

标签 python python-2.7 python-requests

我想使用 Python Requests从 url 获取文件并将其用作 post 请求中的多部分编码文件的库。问题是该文件可能非常大 (50MB-2GB),我不想将它加载到内存中。 (上下文 here .)

文档中的以下示例(multipartstream downstream up)我编造了这样的东西:

    with requests.get(big_file_url, stream=True) as f:
        requests.post(upload_url, files={'file': ('filename', f.content)})

但我不确定我是否做对了。它实际上抛出了这个错误——从回溯中编辑:

    with requests.get(big_file_url, stream=True) as f:
    AttributeError: __exit__

有什么建议吗?

最佳答案

正如其他答案已经指出的那样:requests doesn't support POSTing multipart-encoded files without loading them into memory .

要使用 multipart/form-data 上传大文件而不将其加载到内存中,您可以使用 poster :

#!/usr/bin/env python
import sys
from urllib2 import Request, urlopen

from poster.encode import multipart_encode # $ pip install poster
from poster.streaminghttp import register_openers

register_openers() # install openers globally

def report_progress(param, current, total):
    sys.stderr.write("\r%03d%% of %d" % (int(1e2*current/total + .5), total))

url = 'http://example.com/path/'
params = {'file': open(sys.argv[1], "rb"), 'name': 'upload test'}
response = urlopen(Request(url, *multipart_encode(params, cb=report_progress)))
print response.read()

它可以被修改以允许 GET 响应对象而不是本地文件:

import posixpath
import sys
from urllib import unquote
from urllib2 import Request, urlopen
from urlparse import urlsplit

from poster.encode import MultipartParam, multipart_encode # pip install poster
from poster.streaminghttp import register_openers

register_openers() # install openers globally

class MultipartParamNoReset(MultipartParam):
    def reset(self):
        pass # do nothing (to allow self.fileobj without seek() method)

get_url = 'http://example.com/bigfile'
post_url = 'http://example.com/path/'

get_response = urlopen(get_url)
param = MultipartParamNoReset(
    name='file',
    filename=posixpath.basename(unquote(urlsplit(get_url).path)), #XXX \ bslash
    filetype=get_response.headers['Content-Type'],
    filesize=int(get_response.headers['Content-Length']),
    fileobj=get_response)

params = [('name', 'upload test'), param]
datagen, headers = multipart_encode(params, cb=report_progress)
post_response = urlopen(Request(post_url, datagen, headers))
print post_response.read()

此解决方案需要 GET 响应中的有效 Content-Length header (已知文件大小)。如果文件大小未知,则可以使用分 block 传输编码来上传多部分/表单数据内容。使用 requests 库附带的 urllib3.filepost 可以实现类似的解决方案,例如,基于 @AdrienF's answer不使用 poster

关于python - 使用 Python 请求 'bridge' 文件而不加载到内存中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15973204/

相关文章:

Python:如何将 2.7 模块导入 3.4 程序?

使用 Eclipse PyDev 执行两次 Python 脚本

python - 使用 python requests 库网站总是挂起

python - NumPy 数组大小问题

python - ggplot2 hell 与 rpy2-2.0.7 + python 2.6 + r 2.11 (windows 7)

python - 在Python中检查列表中的元素时循环

curl - Python 请求 SSL 认证问题(和 curl)

python - 尝试按类抓取 HTML span 值,但返回错误

python - Python 中**kwargs 的正确使用方法

python - Flask.test_client().post 和 JSON 编码