flaskで複数の引数を要求するpythonスクリプトを実行する方法


元々コマンドライン上で実行していたPythonスクリプトをWebアプリケーションとして実装しようと考えています。  
このファイルには複数の引数を入力する必要があるため、formに入力した値を引数として渡して実行できるようにしたいです。

Webアプリケーションを作成するのは初めてのため、学習コストが少ないと言われているFlaskを利用しようと考えています。  
おそらくflask_restfulとWTFormsを使用すればできると思うのですが、実装例などを教えていただけないでしょうか。




質問の趣旨としては、簡易的であってもWebサーバを立て、その中でFlaskなどのWebアプリを動作させることが主な趣旨でしょうか。  
そして外部端末のWebブラウザからWebアプリを呼び出して、いつでも特定のPythonスクリプトを実行できることが目的と考えて回答いたします。

pythonでWebアプリを作成するフレームワークは複数あります。  
その中から学習コストが低いものをいくつか紹介します。  
下記の他にも様々なフレームワークがありますので、他を検討しても良いでしょう。  
cf:
[PythonでWebアプリ作れるやつのまとめ(8選)](https://zenn.dev/neka_nat/articles/f2f5b6ebeb049a)

# Flask

Flaskのチュートリアルで触れたであろう`Post`処理の中で「複数の引数を要求するpythonスクリプトに引数を渡」せばブラウザ経由でスクリプトを実行できます。  
下記は`my_script.py`の`calculate_bmi`関数に引数を渡して戻り値を表示するFlaskのコード例です。  
`app.py`と`my_script.py`を同一フォルダに配置して実行してください。

**my_script.py**

[code]

    def calculate_bmi(height, weight):
        bmi = weight / ((height/100) ** 2)
        return bmi
    
[/code]

**app.py**

[code]

    from flask import Flask, request
    from my_script import calculate_bmi
    
    app = Flask(__name__)
    
    @app.route('/', methods=['GET'])
    def get():
        return """ 
    <!DOCTYPE html>
    <html>
    <head>
        <title>BMI Calculator</title>
    </head>
    <body>
        <h1>BMI計算機</h1>
        <form action="/" method="POST">
            <label for="height">身長(cm):</label>
            <input type="text" name="height" id="height" required><br><br>
            <label for="weight">体重(kg):</label>
            <input type="text" name="weight" id="weight" required><br><br>
            <input type="submit" value="計算">
        </form>
    </body>
    </html>
    """ 
    
    @app.route('/', methods=['POST'])
    def post():
        height = float(request.form['height'])
        weight = float(request.form['weight'])
        bmi = calculate_bmi(height, weight)
        return f""" 
    <!DOCTYPE html>
    <html>
    <head>
        <title>BMI Result</title>
    </head>
    <body>
        <h1>BMI計算結果</h1>
        <p>あなたのBMIは {bmi} です。</p>
    </body>
    </html>
    """ 
    
    if __name__ == '__main__':
        app.run()
    
[/code]

# Bottle

[Bottle](https://bottlepy.org/docs/dev/)というフレームワークも同様に使えます。  
極めてシンプルな仕組みで、個人的に使用しているので紹介します。  
`pip install bottle`でインストール可能です。  
`app.py`と`my_script.py`を同一フォルダに配置して`python app.py`のように実行してください。

**my_script.py**  
上記と同様

**app.py**

[code]

    from bottle import route, run, request
    from my_script import calculate_bmi
    
    @route('/')
    def get():
        return '''
            <h1>BMI計算機</h1>
            <form action="/" method="POST">
                <label for="height">身長(cm):</label>
                <input type="text" name="height" id="height" required><br><br>
                <label for="weight">体重(kg):</label>
                <input type="text" name="weight" id="weight" required><br><br>
                <input type="submit" value="計算">
            </form>
        '''
    
    @route('/', method='POST')
    def post():
        height = float(request.forms.get('height'))
        weight = float(request.forms.get('weight'))
        bmi = calculate_bmi(height, weight)
        return f'''
            <h1>BMI計算結果</h1>
            <p>あなたのBMIは {bmi} です。</p>
        '''
    
    if __name__ == '__main__':
        run(host='localhost', port=8080, debug=True)
    
[/code]

# Streamlit

htmlを一度も入力せずにWebアプリを作成するフレームワークとして[Streamlit](https://streamlit.io/)がお勧めです。  
簡単な静的サイトであれば、html/css/javascriptを一切使わずにpythonだけで構築可能です。  
`pip install streamlit`でインストール可能です。  
`app.py`と`my_script.py`を同一フォルダに配置して`streamlit run app.py`のように実行してください。

**my_script.py**  
上記と同様

**app.py**

[code]

    import streamlit as st
    from my_script import calculate_bmi
    
    def main():
        st.title("BMI計算機")
        height = st.number_input("身長(cm)", min_value=1.0, max_value=300.0, step=0.1, value=160.0)
        weight = st.number_input("体重(kg)", min_value=1.0, max_value=500.0, step=0.1, value=60.0)
    
        if st.button("計算"):
            bmi = calculate_bmi(height, weight)
            st.write(f"あなたのBMIは {bmi:.2f} です。")
    
    if __name__ == '__main__':
        main()
    
[/code]

