如何用Python编写下载进度指示器?

如何用Python编写下载进度指示器?,python,http,Python,Http,我正在编写一个通过http下载文件的小应用程序(例如,如上所述) 我还想包括一个小的下载进度指示器,显示下载进度的百分比 以下是我的想法: sys.stdout.write(rem_file + "...") urllib.urlretrieve(rem_file, loc_file, reporthook=dlProgress) def dlProgress(count, blockSize, totalSize): percent = int(count

我正在编写一个通过http下载文件的小应用程序(例如,如上所述)

我还想包括一个小的下载进度指示器,显示下载进度的百分比

以下是我的想法:

sys.stdout.write(rem_file + "...") urllib.urlretrieve(rem_file, loc_file, reporthook=dlProgress) def dlProgress(count, blockSize, totalSize): percent = int(count*blockSize*100/totalSize) sys.stdout.write("%2d%%" % percent) sys.stdout.write("\b\b\b") sys.stdout.flush() sys.stdout.write(rem_文件+“…”) urllib.urlretrieve(rem\u文件、loc\u文件、reporthook=dlProgress) def dlProgress(计数、块大小、总大小): 百分比=整数(计数*块大小*100/总大小) sys.stdout.write(“%2d%%”%percent) sys.stdout.write(“\b\b\b”) sys.stdout.flush() 输出:MyFileName。。。9%

还有其他的想法或建议吗

有一件事有点恼人,那就是终端中百分比第一位上的闪烁光标。有没有办法防止这种情况?有没有办法隐藏光标

编辑:

这里有一个更好的选择,使用全局变量作为dlProgress中的文件名和'\r'代码:

global rem_file # global variable to be used in dlProgress urllib.urlretrieve(rem_file, loc_file, reporthook=dlProgress) def dlProgress(count, blockSize, totalSize): percent = int(count*blockSize*100/totalSize) sys.stdout.write("\r" + rem_file + "...%d%%" % percent) sys.stdout.flush() 全局rem#文件#要在dlProgress中使用的全局变量 urllib.urlretrieve(rem\u文件、loc\u文件、reporthook=dlProgress) def dlProgress(计数、块大小、总大小): 百分比=整数(计数*块大小*100/总大小) sys.stdout.write(“\r”+rem_文件+”..%d%%%s) sys.stdout.flush() 输出:MyFileName…9%


光标显示在该行的末尾。更好。

如果您使用
curses
软件包,您可以更好地控制控制台。它在代码复杂度方面的成本也更高,除非您正在开发一个基于控制台的大型应用程序,否则它可能是不必要的

对于一个简单的解决方案,您可以始终将旋转轮放在状态消息的末尾(字符序列
|,\,-,/
,在闪烁的光标下看起来很不错。

您也可以尝试:

sys.stdout.write("\r%2d%%" % percent)
sys.stdout.flush()

在字符串的开头使用单回车,而不是几个空格。光标仍会闪烁,但它会在百分号之后而不是在第一个数字之下闪烁,使用一个控制字符而不是三个控制字符,闪烁的次数可能会减少。

有一个python文本进度条库,您可以使用它发现有用的:

此库提供文本模式进度条。它通常用于显示长时间运行的操作的进度,提供处理正在进行的可视线索

ProgressBar类管理进度,行的格式由多个小部件提供。小部件是一个对象,根据进度的状态可以不同地显示。小部件有三种类型:-字符串,总是显示自己;-ProgressBarWidget,每次更新时可能返回不同的值方法;和-a ProgressBarWidgetHFill类似于ProgressBarWidget,只是它扩展以填充行的剩余宽度

progressbar模块非常易于使用,但功能强大。并且在可用时自动支持自动调整大小等功能


对于小文件,您可能需要有以下行,以避免出现疯狂的百分比:

sys.stdout.write(“\r%2d%%%percent)

sys.stdout.flush()


干杯

我就是这样做的,这可以帮助你: 我使用了以下代码:

url = (<file location>)
file_name = url.split('/')[-1]
u = urllib2.urlopen(url)
f = open(file_name, 'wb')
meta = u.info()
file_size = int(meta.getheaders("Content-Length")[0])
print "Downloading: %s Bytes: %s" % (file_name, file_size)

file_size_dl = 0
block_sz = 8192
while True:
    buffer = u.read(block_sz)
    if not buffer:
        break

    file_size_dl += len(buffer)
    f.write(buffer)
    status = r"%10d [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
    status = status + chr(8)*(len(status)+1)
    print status,

f.close()
url=()
file_name=url.split('/')[-1]
u=urlib2.urlopen(url)
f=打开(文件名“wb”)
meta=u.info()
文件大小=int(meta.getheaders(“内容长度”)[0])
打印“下载:%s字节:%s”%(文件名、文件大小)
文件大小\u dl=0
block_sz=8192
尽管如此:
缓冲区=u.read(块_sz)
如果不是缓冲区:
打破
文件大小dl+=len(缓冲区)
f、 写入(缓冲区)
状态=r“%10d[%3.2f%%]”%(文件大小,文件大小*100./file大小)
状态=状态+chr(8)*(len(状态)+1)
打印状态,
f、 关闭()

像往常一样迟到。下面是一个支持报告进度的实现,比如核心
urlretrieve

import urllib2

def urlretrieve(urllib2_request, filepath, reporthook=None, chunk_size=4096):
    req = urllib2.urlopen(urllib2_request)

    if reporthook:
        # ensure progress method is callable
        if hasattr(reporthook, '__call__'):
            reporthook = None

        try:
            # get response length
            total_size = req.info().getheaders('Content-Length')[0]
        except KeyError:
            reporthook = None

    data = ''
    num_blocks = 0

    with open(filepath, 'w') as f:
        while True:
            data = req.read(chunk_size)
            num_blocks += 1
            if reporthook:
                # report progress
                reporthook(num_blocks, chunk_size, total_size)
            if not data:
                break
            f.write(data)

    # return downloaded length
    return len(data)

值得一提的是,以下是我用来让它工作的代码:

from urllib import urlretrieve
from progressbar import ProgressBar, Percentage, Bar

url = "http://......."
fileName = "file"
pbar = ProgressBar(widgets=[Percentage(), Bar()])
urlretrieve(url, fileName, reporthook=dlProgress)

def dlProgress(count, blockSize, totalSize):
    pbar.update( int(count * blockSize * 100 / totalSize) )

global rem_file
只有在将其绑定到新对象的函数中才有意义
rem_file=…
否则(如果仅读取其值)
global rem_file
是不必要的。您还可以执行/r+flush()在standard out上。我只是根据您提到的终端行为猜测这是在windows中运行的。如果在不同的线程中提示了多个下载,如何在终端中有多个进度条?这只给了我:pbar.update(int(count*blocksize*100/totalSize))名称错误:未定义全局名称“blocksize”。编辑错误。它应该是输入参数。我已更新了答案以反映这一点。谢谢!
def download_progress_hook(count, blockSize, totalSize):
  """A hook to report the progress of a download. This is mostly intended for users with slow internet connections. Reports every 5% change in download progress.
  """
  global last_percent_reported
  percent = int(count * blockSize * 100 / totalSize)

  if last_percent_reported != percent:
    if percent % 5 == 0:
      sys.stdout.write("%s%%" % percent)
      sys.stdout.flush()
    else:
      sys.stdout.write(".")
      sys.stdout.flush()

    last_percent_reported = percent

urlretrieve(url, filename, reporthook=download_progress_hook)