progressbar for urllib.urlretrieve



地震で大変。ライフラインが止まってしまいました。困った困った。



urllib.urlretrieveにはreport_hook引数が用意されていて、callableを渡すとダウンロード状況をコールバックして知らせてくれます。シグネチャはこんな感じです。

report_hook(blocks_read, block_size, total_byte)

total_byteはHTTPヘッダにcontent-lengthが無い場合-1です。

ブロックを読み出すごとにコールバックされるのでその都度ターミナルなりGUIに出力すればurlretrieveのダウンロード状況を表示できます。今回は前に作ったプログレスバークラスを修正してurlretrieve向けのプログレスバークラスを作りました。

実行するとpython.orgからPython2.7のソースを落とします。

# coding: utf-8
import urllib

class ProgressBar:
    def __init__(self, whole, length=30, ch='#', nch=' ', callback=lambda n:n):
        self.whole = whole
        self.length = length
        self.ch = ch
        self.nch = nch
        self.callback = callback
        self.current = None

    def update(self, current):
        self.current = current
        self.callback(self)

    def __repr__(self):
        ret = ''
        end = self.current / float(self.whole)
        x = int(end * self.length)
        p = int(end * 100.0)
        ret = ''.join(['[',
                self.ch * x,
                self.nch * (self.length - x),
                '] %d%%%c' % (p, '\n\r'[0 if p == 100 else 1])
                ])
        return ret
    
    def __call__(self, blkr, blks, totals):
        self.whole = totals
        idx = 1 if blks * blkr > totals else 0
        self.update([blks * blkr, totals][idx])
        

def callback(progressbar):
    print repr(progressbar),

url = 'http://www.google.com/images/srpr/nav_logo37.png' # without content-length
url = 'http://s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif' # with content-length
url = 'http://python.org/ftp/python/2.7.1/Python-2.7.1.tgz' # a bit large file

out = './' + url[url.rindex('/') + 1:]

urllib.urlretrieve(url, out, ProgressBar(None, callback=callback))


ところでエントリの下書き中にセッションが切れたらしく「下書き保存」を押したらブログトップに飛ばされて下書きが全部消えたので文章がなげやりに。
webインタフェースで編集するとアクシデントで下書きが全部消える事が多いからもうwebインタフェースから編集するのはやめよう・・・