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