最近pythonでの簡単なサーバの作り方をよく調べています。
その中で画面を自動更新できるライブラリである「livereload」というものを知ったので、今回はそれについての備忘録になります。
詳しい情報は参考資料に挙げているページ制作者様のGithubなどを参照してください。
では、始めます。
1:livereloadについて
livereloadは対象ファイルが更新された場合に処理を実行させ、その処理が終わった後にWebページのreloadが行われるようにするためのライブラリです。
日本語で説明すると少しごちゃごちゃしていますが、要は以下のような処理ができるようになります。
- 対象ファイルが更新される
- 更新時の処理を実行
- Webページ更新
例えば「1つページしか存在しないようなWebページサーバで定期的に何かデータを受信してその値を画面に表示させる」というようなものを作りたい場合、このlivereloadを使えば比較的簡単に実装できます。
2:livereloadのインストール
インストールは簡単で以下のpipコマンドでインストールできます。
pip install livereload
3:livereloadの使い方
livereloadの使い方は簡単で、以下のように書きます。
from livereload import Server # livereloadライブラリ読み込み def reload(): # 画面更新前に行いたい処理の関数 pass server = Server() # 引数filepathには監視対象のファイルパス、funcには監視対象ファイルが更新された時に実行する関数を設定 server.watch(filepath="target.txt", func=reload) # 引数hostにはホスト名、portにはポート番号、rootには表示するHTMLファイルを設定 server.serve(host="ホスト名", port=4000, root="index.html")
上記の内容を見ればわかるかと思いますが、livereloadのserver.watchのfilepath引数でlivereloadで監視するファイルを指定します。そしてfunc引数には画面更新前に実行させたい関数を指定します。
その後server.serveでホスト名とポート、表示させたいHTMLファイルを指定して実行することで、livereloadのサーバを起動させることができます。
4:livereloadを使ったサンプル
では実際にlivereloadのサンプルを作って実行してみます。
以下の「template.html」と「page_livereload.py」のファイルを作成し、同じフォルダ内(同じ階層)に格納してください。
・template.html
<html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Cache-Control" content="no-cache"> <title>livereloadのテスト</title> </head> <body> 画面更新回数:$count </body> </html>
・page_livereload.py
# -*- coding: utf-8 -*- import os import platform import socket import threading import time from string import Template from livereload import Server # livereloadライブラリ読み込み # 画面を自動更新するクラス class PageLiveReload: TEMPLATE_PATH = "template.html" UPDATE_FILE_PATH = "target.txt" DISPLAY_HTML_PATH = "index.html" PORT_NUM = 4000 _ipaddress = "" _template = None _target_path = "" _display_html_path = "" _update_count = 0 # 画面更新カウント数 def __init__(self): # コンストラクタ(何もしない) pass def get_ipadress(self): # IPアドレスを取得する関数 ipaddress = "" if platform.system() == "Windows": # Windowsの場合のIPアドレス取得 host = socket.gethostname() ipaddress = socket.gethostbyname(host) elif platform.system() == "Linux": # Linuxの場合のIPアドレス取得 connect_interface = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) connect_interface.connect(("8.8.8.8", 80)) ipaddress = connect_interface.getsockname()[0] connect_interface.close() return ipaddress def setup(self): # 本ファイルまでのディレクトリのパスを取得 base_dir = os.path.dirname(os.path.abspath(__file__)) # テンプレートとなるhtmlを読み込む template_html_path = os.path.join(base_dir, self.TEMPLATE_PATH) self._template = Template(open(template_html_path, "r", encoding="utf-8").read()) # 画面更新判断用ファイルパスの設定 self._target_path = os.path.join(base_dir, self.UPDATE_FILE_PATH) # 画面表示させるHTMLファイルパスの設定 self._display_html_path = os.path.join(base_dir, self.DISPLAY_HTML_PATH) # IPアドレスを取得 self._ipaddress = self.get_ipadress() # 更新判断用ファイルを作成 with open(self._target_path, mode='w', encoding="utf-8") as f: f.write("") # HTMLを初期化(作成) self.update_html() def main(self): server = Server() # 引数filepathには監視対象のファイルパス、funcには監視対象ファイルが更新された時に実行する関数を設定 server.watch(filepath=self._target_path, func=self.reload) # Webページのアドレスをprintで表示 print("http://" + self._ipaddress + ":" + str(self.PORT_NUM)) # 引数hostにはホスト名、portにはポート番号、rootには表示するHTMLファイルを設定 server.serve(host=self._ipaddress, port=self.PORT_NUM, root=self._display_html_path) def reload(self): # 監視対象ファイルが更新された時に実行する関数(この関数実行後にページがreloadされる) # カウントアップ self._update_count += 1 # HTML更新 self.update_html() def update_html(self): # テンプレートから表示させるHTMLの内容を取得 html_content = self._template.safe_substitute(count=str(self._update_count)) # HTMLファイルに書き込み with open(self._display_html_path, mode='w', encoding="utf-8") as f: f.write(html_content) if __name__ == '__main__': # 準備 page_reload = PageLiveReload() page_reload.setup() # マルチスレッドでlivereloadのサーバを実行 web_reload_thread = threading.Thread(target=page_reload.main, daemon=True) web_reload_thread.start() # 無限ループ while True: time.sleep(10) # 10秒毎に画面を更新させる with open(page_reload._target_path, mode='w', encoding="utf-8") as f: f.write("")
内容を少し解説すると、templare.htmlをテンプレートとして読み込み、livereloadで画面更新する際にカウントアップしたものを表示させるということをやっています。
また画面の更新は「if __name__ == '__main__':」内に書いてあるようにおよそ10秒毎にしています。
この2つのファイルを同じ階層に配置できたら、その階層まで移動して以下のコマンドで実行します。
python page_livereload.py
実行するとURLがprint表示されるのでそのページをブラウザで開きます。
ブラウザを開くと以下のように画面更新回数が表示されます。
ブラウザを開いた状態で何もせずに待っていると、およそ10秒毎に画面が更新されて数値がカウントアップされていくようになっているはずです。
5:livereloadを使う際の注意点
livereloadは便利ですが、注意点があります。
それは以下のissueに書いてあるように「短い時間に監視対象ファイルが更新された場合、画面更新が無視される」というものです。
ソースコードを見ると3秒以内に監視対象ファイルが更新された場合はlivereloadによる処理は実行されないようです。
なので、更新タイミングが短くなることが予想される場合には今回のサンプルのように別途10秒毎に画面を更新するなどの対策が必要になります。
また自分の環境だけかもしれませんが、Raspberry Pi OS(64bit)の環境でこのlivereloadを使おうとするとエラーが出て使えませんでした。
Raspberry Pi OS(32bit)だと使えたので、32bitと64bitの違いで使えたり使えなかったりする可能性もあるので注意してください。
以上がlivereloadを使って画面を自動更新する方法になります。
限定的といえば限定的かもしれませんが、ちょっとしたWebページ用サーバであれば割と簡単にかけるこの方法でやってもよいのではないかと思います。
・参考資料