2006 年 7 月 29 日 0 時 4 分

文字列処理


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


今日は、最新日記一覧ページの HTML を取得し、
日記の情報を抜き出してみよう。

最新日記一覧ページには色々な情報があるが、
mixi の HTML は、人間が読むために最適化されているため、
要点だけ抜き出すためには、HTML を解析する必要がある。

日記の情報を取り出すためには幾つかの方法があるが、
今日は、昔からの文字列処理を使ってみる。
前後のテキストを手ががりとして、
取り出したい情報を抜き出すことにしよう。

まず、HTML のソースをじっくり眺めてみる。
日記一覧ページからは、日記の以下の情報が取り出せそうだ。

 ・日時
 ・タイトル
 ・本文の先頭部分

日付は「<font COLOR=#996600>」の後から始まり、
「<br>」の前までだ。
時間はその「<br>」の後から始まり、
「</font>」の前までだ。

タイトルは「<td bgcolor=#F2DDB7> 」の後から始まり、
「</td>」の前までだ。

本文要約は「<td CLASS=h120>改行」の後から始まり、
「改行<br>改行改行</td>」の前までだ。

日記の最初に来るのは日付であり、
その後に時間、タイトル、本文要約と続く。

日付の「<font COLOR=#996600>」というのは一般的なので、
日付以外の場所で使われる危険性はあるのだが、
HTML を調べても日付以外では使用されていないようだ。
ま、どの道 mixi の仕様が変われば対応しなおしなので、
今回は上記を基準として考えよう。

では、テスト用のコードを書いてみよう。

========== Main.js ==========

// 文字列に挟まれた文字列とその最後の位置を配列で返す
function _extract(string, preMatch, postMatch, index) {

    // 直前のパターンを探す
    var start = string.indexOf(preMatch, index);
    if (start == -1) return null;

    // データの開始位置はパターンの後
    start += preMatch.length;
   
    // 直後のパターンを探す
    var end = string.indexOf(postMatch, start);
    if (end == -1) return null;
   
    // 発見
    return [string.substring(start, end), end];
}

function main() {

    // ログイン
    var session = new MixiSession(
            "自分のメールアドレス", "パスワード");

    // 日記一覧ページの HTML を取得
    var html = session.fetch("http://mixi.jp/list_diary.pl");

    // HTML 解析の手掛かりを用意

    // 日付の前後の HTML
    var PRE_DATE = "<font COLOR=#996600>";
    var POST_DATE = "<br>";

    // 時間の前後の HTML
    var PRE_TIME = "<br>";
    var POST_TIME = "</font>";

    // タイトルの前後の HTML
    var PRE_TITLE = "<td bgcolor=#F2DDB7> ";
    var POST_TITLE = "</td>";

    // 要約の前後の HTML
    var PRE_SUMMARY = "<td CLASS=h120>\n";
    var POST_SUMMARY = "\n<br>\n\n</td>";


    // 次の検索位置
    var next = 0;

    for (;;) {

        // 日付を探す
        var date = _extract(html, PRE_DATE, POST_DATE, next);
        if (date == null) break;

        // 時間を探す
        var time = _extract(html, PRE_TIME, POST_TIME, date[1]);
        if (time == null) break;

        // タイトルを探す
        var title = _extract(html, PRE_TITLE, POST_TITLE, time[1]);
        if (title == null) break;

        // 要約を探す
        var summary = _extract(html, PRE_SUMMARY, POST_SUMMARY, title[1]);
        if (summary == null) break;

        // 日記発見!
   
        // テスト出力
   
        WScript.Echo("================================");
        WScript.Echo("日時: " + date[0] + " " + time[0]);
        WScript.Echo("タイトル: " + title[0]);
        WScript.Echo("--------------------------------");
        WScript.Echo(summary[0]);
        WScript.Echo("================================");

        // 次の検索位置を決める
        next = summary[1] + POST_SUMMARY.length;

    }   

}

main();

========== end of Main.js ==========

文字列の検索は、String 型が持つ、
indexOf メソッドを使うのが基本となる。
indexOf は文字列の中に含まれる文字列を検索し、
見つかった文字列の先頭の位置を返す。

そのままコードを書くと indexOf だらけになるので、
2 つの文字列の間に挟まれた文字列を検索する、
関数 _extract を作成することにした。

_extract では、string の index 番目から、
preMatch と postMatch で挟まれる文字列を検索し、
見つかれば、その挟まれた文字列と、
挟まれた文字列の最後の位置を配列で返す。
見つからなければ null を返す。

関数からは複数の値を返したいので、
Perl のように配列を返すようにした。
JavaScript でも大括弧を使って配列リテラルが書けるのだ。

main では、日付・時間・タイトル・要約の 4 項目に対して、
パターンとなる文字列を決めておき、
それを基準として順番に抜き出している。

全て抜き出せた場合は、日記が見つかったので、
テストのために画面出力している。

では、実行してみよう。

================================
日時: 07月27日 22:38
タイトル: 最新日記一覧ページの取得
--------------------------------

さて、長々と脱線していたので、話を軌道に<br>戻そう。今日は MixiSession の実装をする<br>。まず、以前作った _encodeForm 関数を、
================================
================================
日時: 07月26日 18:27
タイトル: プロトタイプ
--------------------------------

JavaScript はオブジェクト指向である。し<br>かし、Java や C# のようなクラスベースで<br>はなく、プロトタイプベースの言語である。
================================

(以下省略)

よし、目的に近づいてきた。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.