よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

【Windows10とAndroid】Pythonとbottleで動かすポンコツWebメモ帳アプリ

入力フォームをつけたページをブラウザで開いて入力送信すると、その内容がローカルのファイルに保存されるだけの記入内容編集不可ポンコツWebアプリを作った。その記録。



【使い方】 Pythonファイルを実行するとブラウザが起動しこのページを表示

f:id:chayarokurokuro:20191104235613j:plain



フォームに入力したら送信ボタンを押す

f:id:chayarokurokuro:20191104235735j:plain



送信内容の表示

f:id:chayarokurokuro:20191104235804j:plain


backで最初の画面に戻る。


ターミナルで入力内容の保存ファイルを開いてるところ

f:id:chayarokurokuro:20191104235911j:plain


入力内容のファイル

f:id:chayarokurokuro:20191105000003j:plain



目次




実行環境


Windows10
Python3.7
ブラウザChrome

Androidスマホ
termux
Python3.7
ブラウザFirefox



作動確認
Windows10とAndroidスマホのtermuxで動作確認しました。OSに応じてブラウザが自動で起動する仕様ですが、Android用はtermuxのコマンドを使っている為、termuxがないと動かない。エラー未対応。コードからブラウザ起動の部分を削除すればたぶん動く



bottleの準備について


Webフレームワークbottleを使います。pip install bottleしてPythonインタープリタからimport bottleで確認しno moduleの警告が出るようなら、bottleの公式サイトから「bottle.py」をダウンロードして(ソースコードをbottle.pyで保存でもOK)、実行用Pythonファイルと同じフォルダに置いておけば動きます。



作るもの


  1. ファイル保存用フォルダ(この中に以下のファイルを保存しておく)
  2. index.html(入力フォーム)
  3. output.html(入力内容表示)
  4. main.py(実行Pythonファイル)



(1)フォルダを作ったら、その中に(2)(3)(4)を作って使います。



実行方法と動作


実行はコマンドプロンプトやtermux等ターミナルから行います。

python main.py


  1. 実行すると入力内容を保存する為のファイル用フォルダが作成されます。
  2. ブラウザが立ち上がりindex.htmlが表示されます。
  3. ブラウザでフォームに入力送信するとmain.pyが処理しブラウザはoutput.htmlを表示します。
  4. main.pyは受け取った入力内容をファイルに書き出します。



index.html作成


先に適当なフォルダを作ってその中にこのファイルを保存します。

<!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>Document</title>
</head>

<body>
    <form action="/output" method="post" accept-charset="UTF-8">

        <p>【投稿欄】<br>
            <textarea name="example1" id="example" cols="40" rows="8" wrap=hard ></textarea></p>

        <p><input type="submit" value="送信する"></p>
    </form>

</body>
</html>



output.html作成


これも同じフォルダに保存

<!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>Output</title>
</head>
<body>
<pre>{{text}}</pre>
<br><br><br>
<a href= "http://localhost:8080/hello" >back</a>
</body>
</html>



main.py作成


これも同じフォルダに保存

from bottle import route,template,run,request
import os
import webbrowser
import subprocess
import time
import threading

# 投稿保存用フォルダ作成
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
    
    #サーバ起動のタイムラグ合わせ
    time.sleep(1)
    
    # 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())

# txtファイル書き込み
def write_txt_log(text):
    #textを「log_folder」内にファイル出力
    with open("./log_folder/log.txt","a",encoding="utf8",newline="\n" ) as f:
        f.writelines(text + "\n")



# bottle API
@route('/hello',method=["GET", "POST"])
def index():
    return template('index.html')

@route('/output',method=["GET", "POST"])
def output():
    # textを取得
    text = request.forms.example1

    #テキストで書き出し
    write_txt_log(text)

    return template('output.html',text=text)

### 実行 ###
thd = threading.Thread(target = open_browser
)

make_log_folder()
thd.start()
run(host='localhost',port=8080,reloader=False,debug=True)



備考


index.html
textareaタグのcols,rowsの数値を変えると入力フォームのサイズが変えられる。wrapは改行対策。



output.html
{{text}}をpreタグで囲まないと入力時の改行がブラウザでの表示に反映しない。



main.py
実行するとブラウザのタブが2つ起動したのでライブラリのtime,threadingを作ったが、たぶん意味ないかも。bottleのrun()関数のreloaderをオフにしたら直ったのでFalseにしている。わからん。
【追記】
「bottle公式 プラグイン」「AUTO RELOADING」の項目に「2回実行されるからBe Careful」と書いてありますた(読んでないのがバレた)。ブラウザのタブが2つ起動する理由はこれだ。



output()を定義した箇所のmethod='POST'だけだとエラーが出たのでmethod=['GET','POST']にした。
またその中のtext = request.forms.example1request.forms.get("example1")でやると文字化けしたのでgetを外した。



おわりに


入力内容の書き出しをテキストファイルで行うと、それを再利用したいとき文字列操作が必要で面倒ですね。途中でjsonsqlでやろうかと思ったが今回は結局やらずじまい。
少しだけWebアプリの理解が深まった。ポンコツでも役に立つ(笑)

以上です。