Python请求post的进展

Python请求post的进展,python,python-requests,Python,Python Requests,我正在使用Python请求包上传一个大文件,我找不到任何方法返回上传进度的数据。我见过许多下载文件的进度表,但这些对文件上传不起作用 理想的解决方案是某种回调方法,例如: def progress(percent): print percent r = requests.post(URL, files={'f':hugeFileHandle}, callback=progress) 提前感谢您的帮助:)请求例如: 例子 我从这里得到了代码:。 我把它改了一点,用BytesIO代替Strin

我正在使用Python请求包上传一个大文件,我找不到任何方法返回上传进度的数据。我见过许多下载文件的进度表,但这些对文件上传不起作用

理想的解决方案是某种回调方法,例如:

def progress(percent):
  print percent
r = requests.post(URL, files={'f':hugeFileHandle}, callback=progress)
提前感谢您的帮助:)

请求
例如:

例子
我从这里得到了代码:。 我把它改了一点,用BytesIO代替StringIO

class CancelledError(Exception):
    def __init__(self, msg):
        self.msg = msg
        Exception.__init__(self, msg)

    def __str__(self):
        return self.msg

    __repr__ = __str__

class BufferReader(BytesIO):
    def __init__(self, buf=b'',
                 callback=None,
                 cb_args=(),
                 cb_kwargs={}):
        self._callback = callback
        self._cb_args = cb_args
        self._cb_kwargs = cb_kwargs
        self._progress = 0
        self._len = len(buf)
        BytesIO.__init__(self, buf)

    def __len__(self):
        return self._len

    def read(self, n=-1):
        chunk = BytesIO.read(self, n)
        self._progress += int(len(chunk))
        self._cb_kwargs.update({
            'size'    : self._len,
            'progress': self._progress
        })
        if self._callback:
            try:
                self._callback(*self._cb_args, **self._cb_kwargs)
            except: # catches exception from the callback
                raise CancelledError('The upload was cancelled.')
        return chunk


def progress(size=None, progress=None):
    print("{0} / {1}".format(size, progress))


files = {"upfile": ("file.bin", open("file.bin", 'rb').read())}

(data, ctype) = requests.packages.urllib3.filepost.encode_multipart_formdata(files)

headers = {
    "Content-Type": ctype
}

body = BufferReader(data, progress)
requests.post(url, data=body, headers=headers)

诀窍是,使用urllib3中的encode_multipart_formdata()从文件列表手动生成数据和头文件。通常,您将构建一个流数据源(生成器),读取分块的文件并报告其进度(请参阅。这不适用于请求文件api,因为请求不支持流式上载(请参阅)–要上载的文件需要在内存中完成,然后才能开始处理

但是请求可以像J.F.Sebastian之前所证明的那样从生成器中流式传输内容,但是这个生成器需要生成完整的数据流,包括多部分编码和边界。这就是发挥作用的地方

poster最初用于pythons,支持多部分请求的流式生成,并在过程中提供进度指示。Posters主页提供了将其与urllib2一起使用的示例,但您确实不想使用urllib2。有关如何使用urllib2.horr进行HTTP基本身份验证的信息,请查看此信息可恢复的

因此,我们确实希望将poster与请求一起使用,以跟踪进度进行文件上载。下面是如何:

#加载请求模块,一个简化的http客户端库
导入请求
#加载编码功能
从poster.encode导入多部分编码
#一种适配器,使poster发布的多部分生成器可供请求访问
#基于源代码http://stackoverflow.com/a/13911048/1659732
类IterableToFileAdapter(对象):
定义初始值(自,可编辑):
self.iterator=iter(iterable)
self.length=iterable.total
def读取(自身,大小=-1):
返回下一个(self.iterator,b“”)
定义(自我):
返回自长度
#定义一个助手函数,模拟posters multipart_encode()函数的接口
#但是用类似文件的适配器包装它的生成器
def multipart_encode_用于_请求(参数,边界=无,cb=无):
datagen,headers=multipart_encode(参数、边界、cb)
返回IterableToFileAdapter(datagen),标题
#这是您的进度回调
def进度(参数、当前、总计):
如果不是参数:
返回
#退房http://tcd.netinf.eu/doc/classnilib_1_1encode_1_1MultipartParam.html
#有关param提供给您的属性的完整列表
打印“{0}({1})-{2:d}/{3:d}-{4:.2f}%.”格式(param.name,param.filename,current,total,float(current)/float(total)*100)
#生成标头和gata生成器请求兼容格式
#并提供我们的进度回访
datagen,headers=用于请求的多部分编码({
“输入文件”:打开('recordings/really large.mp4',“rb”),
“另一个输入文件”:打开('recordings/甚至更大的.mp4',“rb”),
“字段”:“值”,
“另一个字段”:“另一个值”,
},cb=进度)
#使用requests库发出post请求,并附加out数据
r=请求数.post(
'https://httpbin.org/post',
auth=('user','password'),
data=datagen,
标题=标题
)
#显示响应代码和-正文
打印r,r文本

我建议使用名为的工具包,这使得监控上传字节非常容易,如

from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
import requests

def my_callback(monitor):
    # Your callback function
    print monitor.bytes_read

e = MultipartEncoder(
    fields={'field0': 'value', 'field1': 'value',
            'field2': ('filename', open('file.py', 'rb'), 'text/plain')}
    )
m = MultipartEncoderMonitor(e, my_callback)

r = requests.post('http://httpbin.org/post', data=m,
                  headers={'Content-Type': m.content_type})

您可能需要阅读以显示进度条。

我的上载服务器不支持区块编码,因此我提出了此解决方案。它基本上只是python
IOBase
的包装,允许
tqdm.wrapattr
无缝工作

导入io
导入请求
从键入导入联合
从TQM导入TQM
从tqdm.utils导入CallbackIOWrapper
类UploadChunksIterator(Iterable):
"""
这是python请求和TQM之间的接口。
使tqdm像IOBase for requests lib一样被访问。
"""
定义初始化__(
self,file:Union[io.BufferedReader,CallbackIOWrapper],总大小:int,块大小:int=16*1024
):#16MB
self.file=文件
self.chunk\u size=chunk\u size
self.total\u size=总大小
定义(自我):
回归自我
定义下一个(自我):
data=self.file.read(self.chunk\u大小)
如果没有数据:
提出停止迭代
返回数据
#我们不从io.BufferedReader检索len,因为CallbackIOWrapper只有read()方法。
定义(自我):
返回self.total\u大小
fp=“data/mydata.mp4”
s3url=“example.com”
_安静=错误
以开放式(fp,“rb”)作为f:
total_size=os.fstat(f.fileno()).st_size
如果不安静:
f=tqdm.wrapattr(f,“读取”,desc=hv,miniters=1,total=total_size,ascii=True)
以f作为f_iter:
res=requests.put(
url=s3url,
数据=上传ChunkSiterator(f_iter,总大小=总大小),
)
res.为_状态提高_()

我知道这是一个老问题,但我在其他任何地方都找不到简单的答案,所以希望这能帮助其他人:

import requests
import tqdm    
with open(file_name, 'rb') as f:
        r = requests.post(url, data=tqdm(f.readlines()))

从信息进度条的角度让@jfs的答案更好

导入数学
导入操作系统
导入请求
导入系统
课程进度上传:
def uuu init uuuu(self,filename,chunk_size=1250):
self.filename=文件名
self.chunk\u size=chunk\u size
self.file_size=os.path.getsize(文件名)
self.size\u read=0
self.divisor=min(math.floor(math.log(self.file_size,1000))*3,9)#上限单位为GB
self.unit={0:B',3:KB',6:MB',9:GB'}[self.divisor]
自除数=10**自除数
def______________(se
class CancelledError(Exception):
    def __init__(self, msg):
        self.msg = msg
        Exception.__init__(self, msg)

    def __str__(self):
        return self.msg

    __repr__ = __str__

class BufferReader(BytesIO):
    def __init__(self, buf=b'',
                 callback=None,
                 cb_args=(),
                 cb_kwargs={}):
        self._callback = callback
        self._cb_args = cb_args
        self._cb_kwargs = cb_kwargs
        self._progress = 0
        self._len = len(buf)
        BytesIO.__init__(self, buf)

    def __len__(self):
        return self._len

    def read(self, n=-1):
        chunk = BytesIO.read(self, n)
        self._progress += int(len(chunk))
        self._cb_kwargs.update({
            'size'    : self._len,
            'progress': self._progress
        })
        if self._callback:
            try:
                self._callback(*self._cb_args, **self._cb_kwargs)
            except: # catches exception from the callback
                raise CancelledError('The upload was cancelled.')
        return chunk


def progress(size=None, progress=None):
    print("{0} / {1}".format(size, progress))


files = {"upfile": ("file.bin", open("file.bin", 'rb').read())}

(data, ctype) = requests.packages.urllib3.filepost.encode_multipart_formdata(files)

headers = {
    "Content-Type": ctype
}

body = BufferReader(data, progress)
requests.post(url, data=body, headers=headers)
from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
import requests

def my_callback(monitor):
    # Your callback function
    print monitor.bytes_read

e = MultipartEncoder(
    fields={'field0': 'value', 'field1': 'value',
            'field2': ('filename', open('file.py', 'rb'), 'text/plain')}
    )
m = MultipartEncoderMonitor(e, my_callback)

r = requests.post('http://httpbin.org/post', data=m,
                  headers={'Content-Type': m.content_type})
import requests
import tqdm    
with open(file_name, 'rb') as f:
        r = requests.post(url, data=tqdm(f.readlines()))
from pathlib import Path
from tqdm import tqdm

import requests
from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor

def upload_file(upload_url, fields, filepath):

    path = Path(filepath)
    total_size = path.stat().st_size
    filename = path.name

    with tqdm(
        desc=filename,
        total=total_size,
        unit="B",
        unit_scale=True,
        unit_divisor=1024,
    ) as bar:
        with open(filepath, "rb") as f:
            fields["file"] = ("filename", f)
            e = MultipartEncoder(fields=fields)
            m = MultipartEncoderMonitor(
                e, lambda monitor: bar.update(monitor.bytes_read - bar.n)
            )
            headers = {"Content-Type": m.content_type}
            requests.post(upload_url, data=m, headers=headers)
upload_url = 'https://uploadurl'
fields = {
  "field1": value1, 
  "field2": value2
}
filepath = '97a6fce8_owners_2018_Van Zandt.csv'

upload_file(upload_url, fields, filepath)