通常您会构建一个流式数据源(一个生成器),它读取分块的文件并在途中报告其进度(请参阅kennethreitz/requests#663。这不适用于请求文件 api,因为请求不支持流式上传(参见kennethreitz/requests#295)——要上传的文件需要在内存中完成,然后才能开始处理。
但是请求可以像 J.F. Sebastian 之前证明的那样从生成器流式传输内容,但是这个生成器需要生成完整的数据流,包括多部分编码和边界。这就是poster 发挥作用的地方。
poster 最初是为与 pythons urllib2 一起使用而编写的,并支持多部分请求的流式生成,并提供进度指示。海报主页提供了与 urllib2 一起使用的示例,但您真的不想使用 urllib2。查看此example-code,了解如何使用 urllib2 进行 HTTP 基本身份验证。太可怕了。
所以我们真的希望将海报与请求一起使用,以跟踪进度进行文件上传。方法如下:
# load requests-module, a streamlined http-client lib
import requests
# load posters encode-function
from poster.encode import multipart_encode
# an adapter which makes the multipart-generator issued by poster accessable to requests
# based upon code from http://stackoverflow.com/a/13911048/1659732
class IterableToFileAdapter(object):
def __init__(self, iterable):
self.iterator = iter(iterable)
self.length = iterable.total
def read(self, size=-1):
return next(self.iterator, b'')
def __len__(self):
return self.length
# define a helper function simulating the interface of posters multipart_encode()-function
# but wrapping its generator with the file-like adapter
def multipart_encode_for_requests(params, boundary=None, cb=None):
datagen, headers = multipart_encode(params, boundary, cb)
return IterableToFileAdapter(datagen), headers
# this is your progress callback
def progress(param, current, total):
if not param:
return
# check out http://tcd.netinf.eu/doc/classnilib_1_1encode_1_1MultipartParam.html
# for a complete list of the properties param provides to you
print "{0} ({1}) - {2:d}/{3:d} - {4:.2f}%".format(param.name, param.filename, current, total, float(current)/float(total)*100)
# generate headers and gata-generator an a requests-compatible format
# and provide our progress-callback
datagen, headers = multipart_encode_for_requests({
"input_file": open('recordings/really-large.mp4', "rb"),
"another_input_file": open('recordings/even-larger.mp4', "rb"),
"field": "value",
"another_field": "another_value",
}, cb=progress)
# use the requests-lib to issue a post-request with out data attached
r = requests.post(
'https://httpbin.org/post',
auth=('user', 'password'),
data=datagen,
headers=headers
)
# show response-code and -body
print r, r.text