前回、Pythonを使ったWebサイトを作成する手順を紹介した。とはいえ、簡単なメッセージを表示するだけで面白くない。そこで、今回は、スマートフォンでも更新できるメッセージボードを作ってみよう。
WebブラウザとWebアプリのやりとり
Pythonのプログラムを、Webサーバ上で動かすなら、それは『Webアプリ』だ。Webアプリでは、サイトを訪問するユーザが使うWebブラウザとPythonのプログラムのやりとりで成り立っていく。それは、つまり、HTMLの中に、ユーザーの選択に応じてWebブラウザがパラメータを送信するようにしておいて、パラメータを受信したときに、Pythonのプログラムで処理するようにするということを意味する。
そもそも、Webの世界は、HTTPという規約に則って動いている。HTTPは、リクエスト(要求)とレスポンス(応答)の一セットが基本だ。WebブラウザがWebサーバに対して、リクエストを送ると、サーバはリクエストに応じたレスポンスを返す。これの連続でWebは成り立っている。
そして、Webアプリを作るなら、Webサーバ側にあるPythonプログラムによって、レスポンスをフレキシブルに変更できるようになる。以下の図で確認してみよう。最初にユーザは、PythonのプログラムがあるWebサーバにブラウザでアクセスを行う。このときは、何もパラメータはついていない。このとき、Python側では、パラメータなしに応じたHTMLファイルを返す。そして、ユーザーは、HTMLを確認して、テキストを書き込んだり、チェックボックスを操作して、最後に送信ボタンを押す。すると、Webブラウザは、Webサーバに対して、パラメータ付きのリクエストを送信する。Python側では、パラメータを確認して、そのパラメータに応じたHTMLを生成してレスポンスとして返信するという流れになる。
Pythonでパラメータ付きのCGIを作るとき
そして、これは『CGI(Common Gateway Interface)』という仕組みだ。それで、PythonでCGIを作るときには、cgiモジュールを利用すると、手軽にCGIを作ることができる。Pythonには、最初からこのモジュールが用意されている。
それで、WebブラウザからCGIに対して、手軽にパラメータを与えるには、URLパラメータを使うと良い。これは、WebブラウザのURLアドレス欄を利用してパラメータを設定できる。例えば、「https://example.com/app.py」というプログラムに、パラメータを与えるには、以下のような値を入力する。例えば、パラメータaに30を、bに50を与えてみよう。
https://example.com/app.py?a=30&b=50
このように、URLの末尾に「?」を付け、「?変数名1=値1&変数名2=値2&変数名3=値3...」のような書式でパラメータを与えることができる。
そして、このパラメータを受け取るプログラムは、以下のようなPythonプログラムとなる。以下のプログラムを「param.py」という名前で、cgi-binというフォルダに保存しよう。(macOSで試す場合は、一行目をPython3のインストールパスに書き換えて、chmodで実行権限を付与する必要がある。)
#!/usr/local/bin/python3.4
# 日本語を扱うために必要な設定 --- (*1)
import os, sys, io, cgi
sys.stdin, sys.stdout, sys.etderr = [
open(sys.stdin.fileno(), 'r', encoding='UTF-8'),
open(sys.stdout.fileno(), 'w', encoding='UTF-8'),
open(sys.stderr.fileno(), 'w', encoding='UTF-8')]
# ヘッダなどを出力 --- (*2)
print("Content-type: text/html; charset=utf-8\r\n\r\n")
print("<html><body><h1>")
# パラメータの値を取得 --- (*3)
form = cgi.FieldStorage()
if ("a" in form) and ("b" in form):
a = form["a"].value
b = form["b"].value
print("a=" + str(a))
print("<br>")
print("b=" + str(b))
else:
print("パラメータがありません。")
print("</h1></body></html>")
ローカルPCでプログラムを動かすには、前回の内容も参考しつつ、以下のpythonコマンドを実行してWebサーバを起動しよう。そして、Webブラウザで『http://localhost:8000/cgi-bin/param.py?a=30&b=50』にアクセスしてみよう。
python -m http.server --cgi
プログラムを確認してみよう。(*1)の部分では、CGIで日本語を入出力するために必要な部分。続いて、(*2)の部分で、HTTPヘッダなどを出力する。続けて、(*3)の部分で、パラメータの値を取得する。cgi.FieldStorage関数を呼び出すと、パラメータを表すオブジェクトを取得する。そして、そのオブジェクトformに対して、form["a"].valueのようにアクセスすると、実際のパラメータを取得できる。
なお、ブラウザのURL欄のパラメータを変更して、実際にPythonで取得する値が変更されるか動作を確かめてみてみよう。
メッセージボードを作ってみよう
それでは、今日の本題であるメッセージボードを作ってみよう。以下がメッセージボードのプログラムだ。「board.py」という名前でcgi-binフォルダに保存しよう。
#!/usr/local/bin/python3.4
# パスワードやデータファイル名を指定 --- (*1)
PASSWORD = 'abcd'
FILE_MSG = 'msg.txt'
# 日本語を扱うために必要な設定 --- (*2)
import os, sys, io, cgi, re
sys.stdin, sys.stdout, sys.etderr = [
open(sys.stdin.fileno(), 'r', encoding='UTF-8'),
open(sys.stdout.fileno(), 'w', encoding='UTF-8'),
open(sys.stderr.fileno(), 'w', encoding='UTF-8')]
out = lambda s: print(s, end="\n")
# ヘッダなどを出力 --- (*3)
out("Content-type: text/html; charset=utf-8")
out("")
out("<html><body bgcolor='#eee'>")
# パラメータの値を取得 --- (*4)
form = cgi.FieldStorage()
if ("pw" in form) and ("msg" in form):
pw = form["pw"].value
msg = form["msg"].value
# パスワードの照合 --- (*5)
if (pw != PASSWORD):
out("パスワードが違います")
else:
# ファイルに保存 ---- (*6)
with open(FILE_MSG, "wt", encoding="utf-8") as f:
f.write(msg)
out("メッセージを変更しました。")
out("<a href='board.py'>戻る</a>")
else:
# メッセージボードを表示
out("<h1>メッセージボード</h1>")
txt = ""
if os.path.exists(FILE_MSG):
# ファイルから読み出して表示 --- (*7)
txt = open(FILE_MSG, "rt", encoding="utf-8").read()
txt = re.sub(r'(\r\n|\r|\n)', "\n", txt)
# フォームを表示 --- (*8)
out("<form>")
out("<textarea style='width:90%' rows='8' name='msg'>" +txt + "</textarea><br>")
out("パスワード: <input type='password' name='pw'>")
out("<input type='submit' value='書き換え'>")
out("</form>")
out("</body></html>")
同じように、ローカルPCでPythonのWebサーバを起動し、WebブラウザでURLにアクセスしよう。すると、以下のように表示される。テキストボックスにメッセージを入力して、パスワードに「abcd」を入れて、「書き換え」ボタンを押すと、メッセージが更新される。
プログラムを確認してみよう。プログラムの(*1)の部分では、パスワードやデータファイル名を指定する。メッセージボードのメッセージを誰でも書き換えられては困ったことになる。そこで、勝手に書き換えられないようパスワードを指定できるようにした。(*2)では、日本語を扱うための設定を指定している。(*3)では、HTTPのヘッダを出力する。
そして、(*4)の部分では、パラメータの値を取得し、(*5)でパスワードの照合を行う。パスワードが合っていれば、(*6)の部分で、ファイルにメッセージを保存する。(*7)の部分では、ファイルからデータを読み出す。
(*8)の部分では、HTMLのフォームを表示する。このとき、ファイルから読み出したテキストデータも埋め込んで表示する。HTMLのフォームを送信してみよう。すると、URLパラメータにフォームの値が設定される。
冒頭で紹介したように、このメッセージボードは、スマートフォンでも利用することができる。このプログラムを、Webサーバにアップロードし、ファイルのパーミッションを変更する。すると、スマートフォンでも使える。
まとめ
以上、今回は、Pythonを使ったWebアプリの例として、メッセージボックスを作ってみた。URLパラメータを利用すると、掲示板やWikiなど、いろいろなWebアプリを作ることができる。また、機会を見て、Webアプリの作り方も紹介するので、お楽しみに。
自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。