自動巡回エージェントを作る(『スタパライフ』 Ver 1.01)
Chapter.15 自動巡回エージェントの仕組み
いよいよAir C によるプログラミングです。
いきなりソースを書き出す前に、Tea-Cup掲示板を巡回するための『tcup』エージェントを例として、基本的な自動巡回エージェントの構造を調べてみましょう。tcup.rの関数群は、だいたい以下に示すような処理を行っています。

・main
C言語ですから、main関数が必ず必要になります。tcup上でのmain関数は、大きく分けて4つのブロックに分かれています。各種変数の初期化、ウェブサーバ(ホスト)との通信の確立、getmessages関数の呼び出し(戻り値が0で無い限り、main関数は繰返しgetmessages関数を呼び出します)、最後にログデータベースの更新です。
注意すべきなのは、ログデータベースの更新処理ですね。getmessages以下の関数群では、ウェブページから新規ログを抜き出す処理を行うわけですが、そのたびに直接ログデータベースを更新するわけではないのです。追記ログを変数に貯めこんでいって、最後にまとめて更新を行っています。checkmessagesで行っているログデータベースのオープン・クローズは、既取得ログかどうかの判別を行うためのものであって、更新処理が目的では無いということを憶えておいてください。
・getmessages
この関数は、ウェブページのダウンロードを行っています。最初に、開始ページの読込であるのか、『次ページ』以降の読み込みであるのかを判別して、それぞれhtmlの読み込みやcgiへのページ要求を発行しています。http_read関数がwhile句の中に入って少しずつページの読み込みを行っていますが、これはエージェントが複数同時に実行された場合に処理時間を独占しないための処理です。掲示板の読み込みの場合、ログだけで数十kb〜100kb以上になったりすることも珍しくありません。
ウェブページのダウンロードが終ると、checkmessagesという関数を呼び出し、ページ解析とログの追記のための処理を行っています。追記対象のログが存在する場合は、ウェブページのhtmlソース中に『次のメッセージ』という表示のinputタグがあるかどうか検索し、getmessages関数の戻り値を設定しています。最後にウェブページを格納している変数を初期化して終わりです。
・checkmesages
tcupエージェント最大の山場です。この関数は、ウェブページを解析し、Tea-Cup掲示板の発言書式と思われるブロックを発見したら、storemessage関数を呼び出しログの追記処理を行います。処理の順番は、以下の通り。
1)qopen関数でログデータベース(Mail Boxファイル)をオープン
2)page_create関数で、ウェブページをPAGE型構造体の変数に格納
3)page_elements関数で、分割されたタグと、タグに含まれるソース(のポインタ)をELEMENTS型構造体の変数に格納
4)page_find_elements関数で、HRタグのみを抽出し、やはりELEMENTS型構造体の変数に格納(Tea-Cup掲示板の発言はHRタグで区切られているためです)
5)HRタグのリストの個数分だけfor句による繰返し処理を行い、HRタグに続くタグとテキストが、Tea-Cupの発言書式と一致しているかチェック。一致する場合は、storemessage関数を呼び出し
6)storemessageの戻り値が0であった場合は、for句による繰返しを終了(storemessageの結果、新規ログであれば1が戻ります。Tea-Cup掲示板はログが追加された順番に並びますので、既存ログが発見された段階で、新規に取り込むべきログはもう無いと判断することができます)
7)page_free関数でPAGE型構造体変数のために確保したメモリを解放
8)qclose関数でログデータベース(Mail Boxファイル)をクローズ
ログの追記に必要な要素を取り出すために、page_element_textやpage_element_attといった関数が使用されています。
・storemessage関数
この関数は、MSGSTACKという変数に対し、更新するログの内容を追記しています。最初にgetmessagedate関数を呼び出してTea-Cup掲示板上の日付の値を取り出し、tm型構造体の変数に日付を変換します。Tea-Cup掲示板は、一意なログの番号を明示的に持っていないため、tcupエージェントは発言の日付と時間を便宜的にログ番号として用います(つまり、発言の日付・時間が重複するようなログは発生しないであろう、という推測が前提となります)。既にログデータベースはオープンされているので、qfind関数を使って同じログ番号を持つメッセージが取得済みであるかどうかチェックし、存在しない場合はMSGSTACKにログの内容を書き込みます。ログの追記が行われた場合は1を、そうでなければ0を戻り値として返します。
・getmessagedate
Tea-Cup掲示板のログから、日付と時間の部分を抜き出し、時間型の値に変換します。
これが、Tea-Cup掲示板のログを解析し、Mail Boxに格納するエージェントの全体像です。一番の難関、あるいは楽しみはウェブページの解析処理の内部仕様の理解です。いろいろなページを解析して、コツを掴んでください。