【Windows10とAndroid】Pythonとbottleで自作するJupyter風ナイスなポンコツWebアプリ
PythonとWebフレームワークbottleを使って、JupyterNotebook風Webアプリを自作した。その記録。
前々回に作ったものを改造。
前回
前々回
なんと、ブラウザ上でPythonコードが実行できます!
htmlを書き換えれば独自のJupyterが作れる。
実行風景
起動画面
Pythonコードを入力中
実行ボタンを押すと…
カレンダー表示コマンドをPythonから…
カレンダーが表示された
グラフをファイル出力するコードを…
実行しても画面上に表示なし
ちゃんと画像ファイル保存されていた
エラーが出た場合はこんな感じ
実行環境
Androidスマホ
termux
Python3.7
ブラウザGoogleChrome
ブラウザを起動させる部分でtermuxがインストールされた前提のAndroidとWindows用に作っています。前々回のちょっと改造しただけなのでWindows10でも動くと思うが未確認。
目次
ライブラリ
- bottle
- os
- webbrowser
- subprocess
bottleはpip install
等でインストールが必要です。
作るもの
- プロジェクトフォルダ(作るファイルの入れ物)
- index.html(入力・出力)
- main.py(実行用Pythonファイル)
(1)を適当な場所に作ったら、中に(2)(3)を入れておきます。
bottle
がno module
の場合は、bottleの公式サイトから bottle.py
をダウンロードするかコードをその名前で保存し、(1)の中に一緒に入れておけば大丈夫です。
実行方法と動作
実行方法
プロジェクトフォルダをカレントディレクトリにしてターミナルから
python main.py
動作の流れ
- 実行
- 入力保存用フォルダ自動作成
- ブラウザ自動起動しindex.html表示
- 入力したら実行ボタンを押す
- フォーム下に標準出力を表示される
- 入力内容は一旦ファイルに上書きで書き出される
- subprocess.PopenでPythonにそのファイルを実行させる
- stdout,stderrをbottleのテンプレートに渡して
- 実行結果をブラウザ表示
機能
いうなれば、Pythonしか実行できない単一のcodeセル
です。
(1)プロジェクトフォルダ作成
適当にフォルダを作ります。
(2)index.html作成
フォルダ(1)に保存
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Python実行アプリ</title> </head> <body> <form action="/hello" method="post" accept-charset="UTF-8"> <p>【python code】<br><p><input type="reset" value="Reset"></p> <textarea name="example1" id="example" cols="40" rows="8" wrap=off style="overflow:auto;"></textarea> <p><input type="submit" value="実行"></p> <pre><p>{{text0}}</p></pre> <pre><p>{{text1}}</p></pre> </form> </body> </html>
(3)main.py作成
これも同じフォルダに保存
from bottle import route,template,run,request import os import webbrowser import subprocess # 投稿保存用フォルダ作成 def make_log_folder(): os.makedirs("log_folder", exist_ok=True) # ブラウザ起動 def open_browser(): #url url = "http://localhost:8080/hello" # osの種類を取得 which_os_name = os.name # osブラウザ起動 if which_os_name == "nt": # windows webbrowser.open(url) elif which_os_name == "posix": # androidでtermuxをインストール済 cmd = "termux-open-url " + url subprocess.run(cmd.split()) # bottle API @route('/hello',method=["GET", "POST"]) def index(): # textを取得 text = request.forms.example1 with open("log_folder/log.py","w") as f: f.writelines(text) # コマンド実行 python_file = "log_folder/log.py" cmd = "python " + python_file proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) # 正常とエラーの標準出力取り出し result = proc.communicate() res0 = result[0] # ok res1 = result[1] # error if isinstance(res0,bytes): res0 = res0.decode("utf-8") return template('index.html',text0=res0,text1=res1) # 実行 make_log_folder() open_browser() run(host='localhost',port=8080,reloader=False,debug=True)
備考
index.html
前回、前々回と基本的に変えていない。textarea
の入力フォームとinput
ボタン。今回はそこにリセットボタンを付けた。
<input type="reset" value="Reset"></p>
を書いておけば、ボタンを押したときに勝手にtextareaの入力をクリアしてくれる。
{{text0}}は正常に実行された時の標準出力が、{{text1}}はエラー時の出力が渡されてレンダリング、置き換わります。
main.py
カレントディレクトリにフォルダ(./log_folder)を作成し、フォーム入力内容を上書き保存で書き込んだファイル(log.py)をそこへ保存する。
subprocess.Popen()でpython ファイル名
を実行させるが、そのファイルパスが参照される。
result = proc.communicate()で正常とエラーの標準出力がタプルで取り出せる。
あとはreturnでテンプレートに渡してやる。
ブラクラ注意!
ブラウザ起動とreloader=Trueの組み合わせ
コードをいじっている最中、ブラウザを大量に起動させてコンピュータをクラッシュさせる通称ブラクラが発生した。
main.pyにブラウザを起動させるコードをつけているが、もしreloader
をTrue
にしておくと何等かの理由でbottleのサーバがストップしたりするたびにrun()関数が何度も呼ばれ、その都度ブラウザが新しいタブを開く。ブラウザクラッシャー発生w
クラッシュしない仕組みを組み込んでおかないといけませんですね。プロはどうしてる( -_・)?だろう?
reloader=False
で!
以上です。