JP / EN

広告
2023/02/06

FlaskでWebサーバを立てるサンプル~最小限のコードで

タグ:python web

Webサーバと言えばApacheやNginxといった既製ソフトウェアを使うことが多いが、 自分で好きな言語で書いたプログラムにWebサーバの役割をさせる、といったこともも当然可能である。 とはいえ1からWebサーバを書くのは骨が折れるので、 PythonではWebフレームワーク Flaskを使うと比較的簡単にWebサーバをやらせられる。

最小の構成~pyファイル1つで立てる

さっそくpythonスクリプト本体から入ると
    from flask import Flask

    app = Flask(__name__)


    @app.route("/")
    def index():
        return "hello"


    if __name__ == "__main__":
        app.run(debug=True, host="127.0.0.1", port=8888)
  
のようなコードを実行すればよい。
説明
  • app = Flask(__name__): appをFlask Webサーバオブジェクトとして初期化
  • @app.route("/"): app.routeで修飾された関数が、対応するurlにアクセスがあったときに呼ばれる。 ここではトップページ相当のルートを設定している
  • return "hello": route設定された関数はテキストやhtmlを返す。
  • app.run(debug=True, host="127.0.0.1", port=8888): デバッグ用にローカルサーバを立てる(この立て方はあくまで開発用・外部からアクセスできないので注意)。


これをpython app.pyで起動したままにして http://localhost:8888/ にウェブブラウザでアクセスし"hello"と表示されたら成功である。 間違ってhttps等にすると繋がらないので注意。

!注意点:app.runについて
Flaskにおけるapp.runは開発・デバッグ用途の暫定的なサーバ機能のためという位置づけである。
これで立てられたサーバは
  • 内部的な実装が処理効率の観点で最適化されていない
  • 複数のプロセスやスレッドを利用した負荷分散機能がない
などの問題があるとのことだ。
これらの問題を回避するためにFlaskでの本番サーバ構築はWeb Server Gateway Interface (WSGI; ウィスキー) との併用する必要がある。WSGIには様々な種類があるが初心者にはシンプルなGunicornがおすすめである。
とはいえ私はローカルネットワークで運用する個人ツールなどは(ファイアウォールでの保護を前提に)app.runで 運用してしまっている。あくまで個人の責任の範囲で使うのがよい。

やや発展:htmlテンプレートも使う


上のやり方は本当に最小限で、このままでは簡単なテキストを表示する以上のことは難しい。
普通のwebサイトではhtmlを表示したいと思うので、まず外部ファイルからhtmlを読み込めるようにする。
とはいえhtmlが表示できるだけではわざわざpythonで自前コードをサーバ化する甲斐がない。 Pythonプログラムの出力(例えばAIで生成した文章や画像・データベースから読んだ値)を表示できるようにしたい、 というのがpythonでwebサービングする目的であることが多いと思われる。 そこで外部htmlをテンプレートとして使用し、さらにpython側で生成したデータを埋め込んで動的に ページを生成できるようにする。

まずディレクトリ構成を次のように準備する。htmlテンプレートはtemplates/以下に置かないと認識されないので注意。
    $ tree
    .
    ├── app.py
    └── templates
        └── general.html
  

次にhtmlテンプレートファイルを用意する。htmlテンプレートはだいたい見慣れたhtmlと同じ書式であるが、 一部に見慣れない{{ 変数名 }}なる書式がある。 ここにはpythonが生成した値をFlaskを通して動的に入れ込むことができる。
    <html>
      <head>
        <title>{{ title }}</title>
      </head>
      <body>
        {{ body }}
      </body>
    </html>
  
  from flask import Flask, render_template

  app = Flask(__name__)


  @app.route("/alive")  # 比較用にテキストベースのページも残した
  def alive():
      return "OK"


  @app.route("/")
  def index():
      data = {  # templateに流し込むデータ
          "title": "index",
          "body": "hello"
      }
      return render_template("general.html", **data)


  if __name__ == "__main__":
      app.run(debug=True, host="127.0.0.1", port=8888)
  
メソッドrender_templateにテンプレートのファイル名と入れるデータを渡す。 ここでは辞書型を**で展開して渡しているが、title="index", body="hello" のように名前付き引数で渡してももちろん良い。

動作確認したバージョン

  • Python 3.7.2
  • Flask==1.1.2


このエントリーをはてなブックマークに追加

https://wonderhorn.net/