前回、Pythonを使ったWebサイトを作成する手順を紹介した。とはいえ、簡単なメッセージを表示するだけで面白くない。そこで、今回は、スマートフォンでも更新できるメッセージボードを作ってみよう。

  • 今回作るメッセージボード

    今回作るメッセージボード

WebブラウザとWebアプリのやりとり

Pythonのプログラムを、Webサーバ上で動かすなら、それは『Webアプリ』だ。Webアプリでは、サイトを訪問するユーザが使うWebブラウザとPythonのプログラムのやりとりで成り立っていく。それは、つまり、HTMLの中に、ユーザーの選択に応じてWebブラウザがパラメータを送信するようにしておいて、パラメータを受信したときに、Pythonのプログラムで処理するようにするということを意味する。

そもそも、Webの世界は、HTTPという規約に則って動いている。HTTPは、リクエスト(要求)とレスポンス(応答)の一セットが基本だ。WebブラウザがWebサーバに対して、リクエストを送ると、サーバはリクエストに応じたレスポンスを返す。これの連続でWebは成り立っている。

  • HTTPの仕組み

    HTTPの仕組み

そして、Webアプリを作るなら、Webサーバ側にあるPythonプログラムによって、レスポンスをフレキシブルに変更できるようになる。以下の図で確認してみよう。最初にユーザは、PythonのプログラムがあるWebサーバにブラウザでアクセスを行う。このときは、何もパラメータはついていない。このとき、Python側では、パラメータなしに応じたHTMLファイルを返す。そして、ユーザーは、HTMLを確認して、テキストを書き込んだり、チェックボックスを操作して、最後に送信ボタンを押す。すると、Webブラウザは、Webサーバに対して、パラメータ付きのリクエストを送信する。Python側では、パラメータを確認して、そのパラメータに応じたHTMLを生成してレスポンスとして返信するという流れになる。

  • WebブラウザとPythonプログラムのやりとり

    WebブラウザとPythonプログラムのやりとり

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
  • Webブラウザでアクセスしたところ|

    Webブラウザでアクセスしたところ

プログラムを確認してみよう。(*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」を入れて、「書き換え」ボタンを押すと、メッセージが更新される。

  • ローカルPCで実行してみたところ

    ローカルPCで実行してみたところ

プログラムを確認してみよう。プログラムの(*1)の部分では、パスワードやデータファイル名を指定する。メッセージボードのメッセージを誰でも書き換えられては困ったことになる。そこで、勝手に書き換えられないようパスワードを指定できるようにした。(*2)では、日本語を扱うための設定を指定している。(*3)では、HTTPのヘッダを出力する。

そして、(*4)の部分では、パラメータの値を取得し、(*5)でパスワードの照合を行う。パスワードが合っていれば、(*6)の部分で、ファイルにメッセージを保存する。(*7)の部分では、ファイルからデータを読み出す。

(*8)の部分では、HTMLのフォームを表示する。このとき、ファイルから読み出したテキストデータも埋め込んで表示する。HTMLのフォームを送信してみよう。すると、URLパラメータにフォームの値が設定される。

冒頭で紹介したように、このメッセージボードは、スマートフォンでも利用することができる。このプログラムを、Webサーバにアップロードし、ファイルのパーミッションを変更する。すると、スマートフォンでも使える。

  • スマートフォンでも利用できる

    スマートフォンでも利用できる

まとめ

以上、今回は、Pythonを使ったWebアプリの例として、メッセージボックスを作ってみた。URLパラメータを利用すると、掲示板やWikiなど、いろいろなWebアプリを作ることができる。また、機会を見て、Webアプリの作り方も紹介するので、お楽しみに。

自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。