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

Python - サードパーティ製ライブラリ
2018年11月10日2:19に更新(約4日前)
2018年11月7日20:36に作成(約6日前)

旧ブログ移行記事です。

概要

プログラムを作っていてちょっとした進捗バーを作りたいことはよくあります。

tqdmを使うことで、簡単に進捗バーを作成できます。

参考リンク

tqdmのGithub
requestsとtqdmを使った進捗バー
printだけで作る進捗バー

tqdmのインストール

pipで簡単にインストールできます。

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 = "https://narito.ninja/?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は柔軟に設定が可能なので、色々試してみるとよいでしょう。

記事にコメントする