如何使用表单数据和文件显示aiohttp POST的进度



这是我的工作代码:

data = aiohttp.FormData()
data.add_field('title', title)
data.add_field('author', user)
data.add_field('upload_file', open(path, 'rb'))
up_session = aiohttp.ClientSession()
async with up_session.post(url="http://example.com/upload.php", data=data) as response:
resp = await response.text()
resp = json.loads(resp)

我想知道的是如何添加某种进度监控到它。我在文档中找不到任何类型的回调,也找不到与multiparttwriter一起工作的生成器(FormData只是multiparttwriter的助手)。我都快疯了。提前谢谢。

编辑:我曾经得到它与请求和requeststoolbelt (MultipartEncoder, MultipartEncoderMonitor),但那些不是异步的,和aiohttp是这样一个完整的库,我不敢相信你不能这样做。

encoder = MultipartEncoder(
fields={
'upload_file': (ntpath.basename(path), open(path, 'rb'), 
'application/octet-stream'),
'title': str(''),
'author': str(user),
})
upload_data = MultipartEncoderMonitor(encoder, upload_progress)
headers={'Content-Type': upload_data.content_type}
headers.update(http_headers)

r_2 = session.post(url=url_domain + "/repository/repository_ajax.php?action=upload", data=upload_data)
def upload_progress(monitor):
print (str(monitor.len) + " - " + "{:.2f}%".format(monitor.bytes_read/monitor.len))

我确实找到了一个解决方案,有点黑客,但它工作,它是一般的其他库不提供良好的进度跟踪,但接受二进制流。它是BufferedReader的包装器。从技术上讲,计算读取而不是发送的字节数,但对于进度条来说,这是一样的。

from pathlib import Path
from io import BufferedReader
from aiohttp import ClientSession

class ProgressFileReader(BufferedReader):
def __init__(self, filename, read_callback=None):
f = open(filename, "rb")
self.__read_callback = read_callback
super().__init__(raw=f)
self.length = Path(filename).stat().st_size
def read(self, size=None):
calc_sz = size
if not calc_sz:
calc_sz = self.length - self.tell()
if self.__read_callback:
self.__read_callback(self.tell(), self.length)
return super(ProgressFileReader, self).read(size)

def progress_callback(current, total):
print(100 * current // total)

async def main():
with ProgressFileReader(filename="./file.jpg", read_callback=progress_callback) as file:
upload_payload = {
"foo": "bar",
"file": file,
}
async with ClientSession() as session:
async with session.post("http://example.org", data=upload_payload) as response:
resp = await response.text()

包装器本身是同步的,但这没什么大不了的,如果你包装aifiles而不是内置的"open",它可以是异步的。包装类的想法归功于其他一些我现在找不到的stackoverflow问题。

最新更新