naritoブログ

このブログはPython/DjangoとBootstrap4で作成されました
Githubのソースコード

Pythonで進捗バーを表示する(tqdm)

約848日前 2016年1月31日5:32
プログラミング関連
tqdm
tqdmを使うことで、簡単に進捗バーを作成できます。

参考リンク


公式ページ
requestsとtqdmを使った進捗バー
printだけで作る進捗バー


tqdmのインストール


pip install tqdm



基本的な使い方


イテラブルなオブジェクトを、tqdm()で囲むことができます
from time import sleep
from tqdm import tqdm


for i in tqdm(range(100)):
    sleep(0.1)



このようになります
進捗が表示される

上の書き方が見た目的にうるさい、と思うならばこういう書き方もできます
from time import sleep
from tqdm import tqdm

my_bar = tqdm(range(100))
for i in my_bar:
    sleep(0.1)




リスト内包表記でも、勿論使えます
[sleep(0.01) for i in tqdm(range(100))]



updateで進捗を進める


進捗バーを自分のタイミングで進めることもできます。
pbar = tqdm(total=100)
for i in range(100):
    pbar.update(1)
pbar.close()


totalに合計の値を、.update()に、進めたい数を入れましょう。
ちなみに上記はすぐに処理が終わるので進捗バーは表示されません。


説明文をつける


進捗バーに、自分で文字を設定することも可能です。
以下のコードには書いてませんが、pbar.update()と併用も可能です。
import time
from tqdm import tqdm


pbar = tqdm(["a", "b", "c", "d"])
for char in pbar:
    pbar.set_description("Processing %s" % char)
    time.sleep(1)


見た目はこのようになります。
進捗バーに説明が足された


実際のサンプル


例えば、このブログの記事見出し(h2タグ)を全て取得し、進捗バーで表示したいならば...
ブログの見出し取得を進捗表示する

from tqdm import tqdm
import requests
from bs4 import BeautifulSoup


page = 1
url = "http://torina.top/?page={}"
h2s = []

# 数えたら、現在70記事ありました。なので70を入れてます
# ここのtotalとupdateには、適当に入れても割とそれっぽくはなります
pbar = tqdm(total=70)
while True:
    res = requests.get(url.format(page))
    soup = BeautifulSoup(res.text, "html5lib")
    pager_text = soup.find("ul", class_="pagination").text

    # <li><a href="?page=2">NEXT</a></li>が
    # pager_textに含まれていれば、次のページ有
    if not "NEXT" in pager_text:
        break
    h2s += [h2 for h2 in soup.find_all("h2")]
    page += 1
    pbar.update(10)  # 私のブログは、1ページ10記事です

pbar.close()
print("すべてのh2タグを取得しました")




注意点


注意点としては、以下のようなコードです。
ジェネレータオブジェクトなど、長さがわからないもの(__len__がない)は少し勝手が変わります。
import time
from tqdm import tqdm


my_range = (x for x in range(10))
for i in tqdm(my_range):
    time.sleep(1)


実行するとこのような表示になります。シンプルになってしまいましたね。むしろ、ちゃんと動作することに感動です。
__len__がなくても動くには動く

単純に解決するならば、set_description()で補い、単位となる「unit」を指定しましょう。
import time
from tqdm import tqdm


pbar = tqdm((x for x in range(10)), unit="range")
for i in pbar:
    pbar.set_description("NowRange {0}".format(str(i)))
    time.sleep(1)



表示は以下になります。
割と見れるようになった

__len__がなくても、長さがわかっている場合はtotal引数に指定することで本来の表示にさせることもできます。
import time
from tqdm import tqdm

my_range = (x for x in range(10))
for i in tqdm(my_range, total=100):
    time.sleep(1)


tqdmは柔軟に設定が可能なので、色々試してみるとよいでしょう。
名無し 約186日前 2017年11月23日11:40 返信する
tqdmの引数にtotalで長さを指定すれば、__len__ methodを持たないイテレータでもプログレスバーの表示は可能ですよ!
なりと 約185日前 2017年11月23日20:40
ありがとうございます、最後に追記しました。