作者: 機械伯爵
日時: 2003/9/28(21:12)
 どうも、ご無沙汰していました、機械です。

 最近、様々な理由からPyPageをいじりだしています。

 PyPageは、Pythonで書かれた小規模・軽量が売りのWeb
サーバです。

 そのためか、ソース内に埋め込まれたドキュメントと
サンプルだけ以外には、ほぼドキュメントらしいドキュ
メントも解説も存在していないようです。

 実際、作者が日本の方ですし、内部ドキュメントは詳
細で判りやすいので、「Pythonテクニカルリファレンス」
あたりを片手にハッキングしていけば、理解できないよ
うなコードは無いようなのですが、「気軽に使える」と
いう魅力を若干生かしきっていないようなのが気になり
ます。

 というわけで、「PythonとHTMLの基礎さえ知ってれば、
ある程度は使える」程度に、PyPageの使い方を紹介して
いきたいと思います。



■その前に・・・Webサーバってナニ?

 え〜、TSNETのMLにご参加の方で、よもやWebサーバを
ご存知無い方などいるはずない・・・と、お思いでしょ
うが、事実私自身が知らなかった(爆)ので、念のためち
こっと説明しておきます(私だけかもしんないけど)

 Webサーバは、IEとかネスケのようなブラウザをクライ
アントとして、両方でハイパーテキストデータベースを
実現するアプリです。ところが、こういったブラウザは、
単独でOSのファイルシステムにアクセスして、ローカル
ファイルを表示したり、リンク・ジャンプをさせたり、
果てにはJavaScriptのようなスクリプトやJavaアプレッ
トのようなプログラム(Flashモジュールとか、もかな?)
まで動かしてしまうので、単なるファイルサーバとどこ
が違うのか、といわれると、実は結構悩んだりします。

 で、一口に言えば、Webサーバを立てると、CGI(Common
Gateway Interface)スクリプトや、SSI(Server Side
Include)スクリプトが使えるページが動きます。

 Javaアプレットや各種HTMLスクリプトは、基本的には
クライアントサイド(ページをダウンロードしたマシン
の上)で実行されますので、セキュリティ管理のため、
ファイル管理などにかなり大きな制限があります。

 しかし、サーバサイドのスクリプトなら、その制限は
事実上ありません。

 無論、インターネットに公開するようなWebサーバを立
ち上げるなら、それなりの知識や技術も必要ですが、HTML
コンテンツをフロントエンドにしてアプリケーションを
作ったり、あるいはLAN内での閲覧用コンテンツを立ち上
げたりと、あまりセキュリティーに目くじらを立てるよ
うなものでない場合は、結構気楽に使えます。



■PyPageとは?

 PyPageとは、標準モジュールのみを使用して書かれた、
PythonスクリプトによるWebサーバです。

 現在、Pythonで書かれている最も有名(日本では、多
分Python本体よりも有名)なWebアプリケーションサーバ
は、ご存知Zopeでしょう。

 というわけで、PyPageの特徴をざっと知っていただく
ために、ざっとZopeと比較してみました。

・機能
 Zope :豊富
 PyPage:最小限度

・マシンパワー
 Zope :やや必要
 PyPage:軽い

・コンテンツ作成
 Zope :Web上で可能
 PyPage:テキストエディタで地味に・・・

・Webページ上のPythonスクリプト
 Zope :DTMLに組み込み可能
 PyPage:不可

・PythonによるCGI/SSIモジュール
 Zope :可能だが、手続きがやや面倒
 PyPage:簡単。ただし、安全性に要注意

・OS依存
 Zope :若干あり
 PyPage:ほぼ無し

 雰囲気としては、ZopeがWebアプリケーションサーバと
して、独立した存在であるのに対し、PyPageは、Python
を用いた動的Webコンテンツのためのフレームワークとい
った印象があります。

 何にしても私にとって嬉しいのは、ローパワーで動く
軽量さと、あまり規約を気にせずにPythonで書かれたモ
ジュールを追加できる自由度にあります。

 それでは、PyPageのさわりの部分を、紹介したいと思
います。

<注意>
 この文章に掲載したスクリプトは、セキュリティや安
定性に関して、かなりはしょってあります。「動く」実
感以上に、ちゃんとしたスクリプトを書かれる場合は、
PyPage付属のサンプルのソースをご参照ください。



■PyPageの立ち上げと、「はじめてのPyPage」

 それでは、使い方です。

 まず、PyJUGのページ(http:www.python.jp/Zope/)から
たどって、PyPageのアーカイブファイルをダウンロード
してきます。

 解凍したフォルダ(ディレクトリ)の中のうち、OSにあ
わせて以下のように起動させます。

 UNIX系の場合は、startd.pyかminserver.pyスクリプト
を起動させます(Mac OS XはUnix扱い)

 Winの場合、NT系(NT4.0,2000,XP)なら、コンソールか
らminserver.pyを立ち上げても良いのですが、マルチプ
ロセスがサポートされていないWin9x系(95,98,ME)の場合
は、Tkを使ったコンソールが立ち上がるstart.pywをダブ
ルクリックして立ち上げた方が、終了させるとき気楽で
しょう。

 PyPageを立ち上げたら、Webブラウザから、
http://localhost:8000/にジャンプしますと、トップペー
ジにアクセスできます(もしこれでアクセスできない場合
は、http://127.0.0.1:8000/からアクセスできます)

 トップページはpubフォルダ下のindex.htmlですので、
このファイルを書き換えればトップページが変更されま
す。

 そこのサンプルやソースを適当に閲覧したら、次に、
実際にPyPageモジュールを作ってみましょう。

 まず、pubフォルダ下に、test0.pyという名前でファイ
ルを作り、以下のように書きます。

#---test0.py---

def page(pc):
  pc.send_head()
  pc.write('''<html>
  <head>
    <title>Hello</title>
  </head>
  <body>
    <h1>Hello PyPage for Python!</h1>
  </body>
  </html>''')

#---test0.py---

 これで、http://localhost:8000/test0 にアクセスす
ると、コンテンツが表示されます。

 HTMLファイルではなくPythonモジュールを指定される
と、PyPageはモジュール内のpage関数を探してそれを実
行します。

 ページは動的に生成されてブラウザに送られます。

 ちなみに、http://localhost:8000/test0.py と拡張子
つきで指定すると、Pythonのスクリプトソースが表示さ
れてしまいますので注意してください。

 page関数の第一パラメータはPyPageContextインスタン
ス(要するにページそのもののオブジェクト)になるので、
このページオブジェクトにsend_headメソッドで、まずヘ
ッダを送ってやり、次にコンテンツ内容をテキストで書
いてwriteメソッドでページオブジェクトに送ってやれば、
そのコンテンツが表示されます。

※コンテンツって、「内容」って意味だから、「コンテ
  ンツ内容」って言葉はかなりヘンだけど・・・



■動的ページを作ってみる

 とりあえず、動的ページを実感すべく、カウンターと
日付や時刻でも入れてみましょうか?

#---test1.py---
from time import ctime

page_context='''<html>
  <head>
    <title>Time and Count!</title>
    <style>
      p{font-size:48pt;text-align:center;color:red}
    </style>
  </head>
  <body>
    <p style="">Hello PyPage for Python!</p>
    <p>TIME=%(time_now)s</p>
    <p>COUNT=%(count_now)d</p>
  </body>
</html>'''

cnt = [1]

def page(pc):
  pc.send_head()
  time_now = ctime()
  count_now = cnt[0]
  cnt[0] += 1
  pc.write(page_context % vars())

#---test1.py---

 文字列オブジェクトに対する % 演算子の拡張表記は、
シーケンスではなく辞書で変換文字のデータを渡せるた
め、スコープ領域の全オブジェクトの辞書を作るvars組
み込み関数と併用すると便利です。

※上の例では、%(time_now)sにtime_nowの内容が、
  %(count_now)dにcount_nowの内容が、それぞれ渡され
  ます。

 カウンタをグローバル変数にするのはなんかヤなので、
リスト参照にしてポインタっぽく使ってます。

 以上、page関数が呼び出された際、文字列を逐次変換
させ、現在値を表示するという非常に簡単な仕組みで、
見た目も動的なページが出来上がりました。



■フォームからリクエストを受け取る

 さて、入力フォームから値を受け取り、それを用いた
表示を行う、という例を行ってみましょう。

 入力フォームのほうは、別に動的にする必要も無いの
で、ここでは素直にHTMLドキュメントを書きます(ファ
イル名はtest2.htmlとでもしましょうか)

<html>
 <head>
  <title>Form Test</title>
 </head>
 <body>
  <form action="test2b" method="post">
   お名前は?<input type="text" name="uname" />
   <input type="submit"/>
  </form>
 </body>
</html>

 次に、名前入りのメッセージを自動生成します。

 メッセージが日本語コードでやりとりされるので、コー
ド変換を行います。

#---test2b.py---

j_mes = unicode("%(u_name)sさん、こんにちは").encode("UTF-8")
page_content='''<html>
 <head>
  <title>Hello!</title>
 </head>
 <body>
  <p>%s</p>
 </body>
</html>''' % j_mes

def page(pc,uname):
  u_name = unicode(str(uname)).encode("UTF-8")
  pc.send_head()
  pc.write(page_context % vars())

#---test2b.py---

 フォームから送られたメッセージは、page関数の引数
としてキャッチされますので、そいつを文字列化してや
ると、メッセージが取り出せるわけですが、ASCIIコード
でない場合は、UNICODE変換を掛けておくほうが無難です
(UNICODEで送られてくるという「滅多に無い」状態を期
待するより)

 フォームからの情報は様々ですが、とりあえずテキス
トやラジオボタンからの情報程度なら、上記のようなコー
ドを書けば十分です。

 なお、<input type="file">のような厄介な形式の場合
については、付属のサンプルスクリプトにありますので、
参照してみてください。

 さて、もう少し書きたいことがあるのですが、やや長
くなりましたので、今回はこのへんにしておきます。

/機械伯爵/