PythonでWebプログラミングの基礎(その8)CGIでファイルの内容を表示する

前回の続きです。前回は画面から入力した内容をCGIのパラメータで受け取ってファイルに保存しました。保存した内容は実際のファイルを見て確認しました。

今回は保存されたファイルの内容をCGIプログラムで画面に表示してみます。CGIプログラムで保存されたファイルを入力として読み込んでその内容を画面に出力します。このファイル入出力の流れがメインテーマです。

処理の流れ
前回作成したプログラムで以下の画面からファイルへ保存します。

ファイルには例えばですが以下のように保存されています。

この内容を以下のように表示します。(※パスワードに関しては、そのまま見える状態で保存されていて、そのまま表示するわけないだろとなりますがここは学習用ということでご了承ください。)

ファイル構成
ファイル構成は以下です。

webserverというディレクトリがここでのWebサーバの起動ディレクトリです。今回のプログラムはread1.pyからread3.pyまでです。

以下がファイル一式です。(※学習用レベルのプログラムです。内容に関しては一切無保証なのでご了承下さい。)
webserverディレクトリ配下のファイル一式

Webサーバの起動方法とCGIプログラム起動方法は以下で書きました。
PythonでWebプログラミングの基礎(その1)Webサーバの動作確認
PythonでWebプログラミングの基礎(その2)CGIで動的ページの表示
ファイルへ保存するプログラムについては以下の記事で書きました。
PythonでWebプログラミングの基礎(その7)CGIでパラメータを保存する

今回のCGIプログラム(最終的な第3段階のプログラム)
今回のCGIプログラムは以下です。これで上記の「ファイルの内容」のブラウザ画面のような内容を表示します。

#!/usr/bin/env python3

#HTMLテキストの上の部分
htmlText1st = '''Content-type: text/html; charset=UTF-8

<html>
<head>
  <title>ファイルの読み込みから表示</title>
  <link rel="stylesheet" href="../style.css">
</head>
<body>
<header class="header">
   <p>ファイルの内容</p>
</header>
<div class="content">
'''

#HTMLテキストの下の部分
htmlText2nd = '''

</div>
</body>
</html>
'''

#ここから処理
import cgi

def main():
    print(htmlText1st)

    f = open('member.txt', 'r')
    line = f.readline()

    print('<table border="1">')
    print('<th>お名前</th><th>ログイン名</th><th>パスワード</th><th>メールアドレス</th>')

    while line:
        print('<tr>')

        items = line.split(',')

        for item in items:
            print('<td>')
            print(item)
            print('</td>')

        print('</tr>')

        line = f.readline()

    f.close()  

    print('</table>')

    print(htmlText2nd)

if __name__ == "__main__":
    main()

今回はmain関数で処理しています。関数に関しては以下に書きました。
Pythonでの関数定義と関数呼び出し

より「品質の高い」「実務的な」プログラムとしては、例外処理(エラー時の処理)やより細かい関数(機能の)分割等も必要ですが、ここでは基本的な学習用のレベルです。

このプログラムを書いた過程とその各過程での結果表示で順番に説明します。

もちろん全て細かく説明出来ませんので必要な場合は以下のPythonマニュアル等を参照して下さい。
Python3のマニュアル(日本語)

ファイルの内容をそのまま表示する(第1段階)
以下のCGIプログラムでは、ファイルをオープンしてファイルの内容を1行ずつでそのまま表示しています。

#!/usr/bin/env python3

#HTMLテキストの上の部分
htmlText1st = '''Content-type: text/html; charset=UTF-8

<html>
<head>
  <title>ファイルの読み込み</title>
  <link rel="stylesheet" href="../style.css">
</head>
<body>
<header class="header">
   <p>ファイルの内容</p>
</header>
<div class="content">
'''

#HTMLテキストの下の部分
htmlText2nd = '''

</div>
</body>
</html>
'''

#ここから処理
import cgi

def main():
    print(htmlText1st)

    f = open('member.txt', 'r')
    line = f.readline()

    while line:
        print(line)
        print('<br/>')

        line = f.readline()

    f.close()  

    print(htmlText2nd)

if __name__ == "__main__":
    main() 

例えばですが、以下のような表示になります。

最初のcatコマンドで表示したファイルの内容の(黒い画面の)スクリーンショットと同じ表示です。まさにファイルの内容そのままです。まずはこれで第一段階ということで処理を見ていきます。

出来れば、上記のPythonでのCGIプログラム部分を紙に印刷するとか別の画面、別のモニタで見比べながら以下の説明を読んで頂ければと思います。

HTMLの構成
レスポンスとして表示させるHTMLテキストを、変数名htmlText1stのヘッダー部分(上部)と変数名htmlText2ndのフッター部分(下部)に分割しました。これで表示処理を以下の3段階に分けて表示します。

ヘッダー部分部分表示
ファイル内容表示
フッター部分表示

これらの表示処理全体でHTMLの表示が完成します。
(ブラウザからから見ることが出来る「ページのソース」がプログラムで表示したHTMLのレスポンスです。)

ファイル内容表示の処理
ファイルのオープンとクローズ
f = open()の行がオープンでfがopen()で返されるファイルオブジェクトです。member.txtというファイルを読み込みモードでオープンしています。1行ごとの読み込みをファイルオブジェクトf(変数f)を使って処理しています。f.close()がファイルクローズです。

ファイルの1行ごとの処理
ファイルから文字列で1行を読み込む処理はreadline()です。lineに1行分の文字列が入って来ます。

while lineの行からから繰り返しです。この場合のwhileは「前判定」という繰り返しで、1行ごとの文字列が続く限り処理を続けるという繰り返しです。

この場合は、whileの前に先に1行読み込んでいるのでオープンしたファイルの内容が空の場合でも問題なく動作します。このようなwhileの流れは実際によく使います。

あと、1行ごとにHTMLの改行である<br/>を表示しています。これでブラウザでも改行されて表示されます。

ファイルの内容をHTMLのtableタグで表示する(第2段階)
第1段階で単純な1行ごとの表示をtableタグで表示します。プログラムは以下です。

#!/usr/bin/env python3

#HTMLテキストの上の部分
htmlText1st = '''Content-type: text/html; charset=UTF-8

<html>
<head>
  <title>ファイルの読み込み</title>
  <link rel="stylesheet" href="../style.css">
</head>
<body>
<header class="header">
   <p>ファイルの内容</p>
</header>
<div class="content">
'''

#HTMLテキストの下の部分
htmlText2nd = '''

</div>
</body>
</html>
'''

#ここから処理
import cgi

def main():
    print(htmlText1st)

    f = open('member.txt', 'r')
    line = f.readline()

    print('<table border="1">')

    while line:
        print('<tr>')

        items = line.split(',')

        for item in items:
            print('<td>')
            print(item)
            print('</td>')

        print('</tr>')

        line = f.readline()

    f.close()  

    print('</table>')

    print(htmlText2nd)

if __name__ == "__main__":
    main() 

例えばですが、以下のように表示されます。

テーブルタグの部分は以下のようなHTMLになります。

<table border="1">
<tr><td>山田太郎</td><td>YTaro</td><td>abcde</td><td>aa@bb.com</td></tr>
<tr><td>鈴木一郎</td><td>SSIchi</td><td>abcdefg</td><td>ss@ss.com</td></tr>
<tr><td>佐藤花子</td><td>SHana</td><td>abc</td><td>hh@ss.com</td></tr>
</table>

こちらも、出来れば上記のPythonでのCGIプログラム部分を紙に印刷するとか別の画面、別のモニタで見比べながら以下の説明を読んで頂ければと思います。

プログラムの説明
第1段階のプログラムでは単純に1行ずつ表示しました。第2段階ではその1行をさらに tr td のタグで要素を囲むという処理を追加します。もちろん、最初と最後に table タグを追加します。

この table タグから各要素の td タグの出力が第2段階のテーマです。

まず、1行ごとに tr と /tr タグを出力しています。そして、line.split(‘,’)でカンマ区切りを要素に分割しています。その要素ごとに td と /td を出力しています。

繰り返しの単位が第1段階ではファイルの1行単位だったのが、第2段階ではさらに1行の要素単位での繰り返しがfor文で追加されています。要素ごとに td と /td を挟むように表示しています。

この繰り返しの段落を字下げと合わせて見てください。また、その段落と table から /table までの実際の表示を見比べて頂ければと思います。

tableの完成(第3段階)
第3段階がこのページ最初のPython CGIプログラムです。

thタグの追加
第3段階としては、th から /th タグでの見出しを追加しました。第3段階とするほどの内容でもないですが、第2段階で table タグの構成を固めてそれが出来た後に th を追加した方が分かりやすいかなと思いました。

table タグの出力の後、1行だけ項目の見出しとして1回だけ表示しています。その部分と最初のファイル出力のスクリーンショットの見出しの部分を確認してみて下さい。

プログラムの説明はここまでです。

今回は以上です。次回は今回のプログラムに例外処理(実行時エラー処理)を追加します。次回に移動する