このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
日記は、view_diary.pl にアクセスすることで取得できる。
このページでは、完全な形で日記を見ることができる。
view_diary.pl の URL のパラメータには、
日記の ID だけでなく、著者の ID も渡す必要があるが、
これら ID は、日記一覧ページから取得できるので問題ない。
では、まずはページを取得して HTML を眺めてみよう。
var session = new MixiSession(
"自分のメールアドレス", "パスワード", 3000);
var html = session.fetch("http://mixi.jp/view_diary.pl",
{ id : 192777686, owner_id : 2300658 } );
WScript.Echo(html);
日記一覧ページからは、以下の情報を取り出す。
・日時
・本文
タイトルは、一覧ページで取得できるので、
改めてここで取得する必要はないと考える。
正規表現を考えてみよう。
日時は、2006年08月07日<BR>19:29 のようになっているので、
年・月・日・時・分 を別々に取り出して後で組み合わせる。
「(\d+)年(\d+)月(\d+)日<BR>(\d+):(\d+)」って感じだ。
本文は、「<td CLASS=h12>」で始まり、「</td>」で終わる。
「<td CLASS=h12>([\w\W]*?)</td>」って感じでいける。
では、上記のラッパ MixiDiaryEntry クラスを作り、
MixiDiary#iterator() が返すイテレータからは、
個々の日記として配列ではなく MixiDiaryEntry を返すように
設計を変更してみよう。
========== MixiDiaryEntry.js ==========
// 日記の正規表現(年・月・日・時・分・本文)
MixiDiaryEntry._REX_DIARY
= "<td ALIGN=center ROWSPAN=2 NOWRAP WIDTH=95 bgcolor=#FFD8B0>"
+ "(\\d+)年(\\d+)月(\\d+)日<BR>(\\d+):(\\d+)</td>"
+ "[\\w\\W]*?"
+ "<td CLASS=h12>([\\w\\W]*?)</td>";
// クラスのコンストラクタ
function MixiDiaryEntry(session, id, ownerID, title) {
// 引数評価 & 格納
if (!(session instanceof MixiSession)) {
throw TypeError("session 引数が不正です。");
}
this._session = session;
this._id = parseInt(id, 10);
this._ownerID = parseInt(ownerID, 10);
this._title = String(title);
// その他フィールド
this._date = undefined;
this._content = undefined;
}
// ID を返す
MixiDiaryEntry.prototype.getID = function () {
return this._id;
}
// 日時を返す
MixiDiaryEntry.prototype.getDate = function () {
if (this._date == undefined) {
this._retrieve();
}
return this._date;
}
// タイトルを返す
MixiDiaryEntry.prototype.getTitle = function () {
return this._title;
}
// 本文を返す
MixiDiaryEntry.prototype.getContent = function () {
if (this._content == undefined) {
this._retrieve();
}
return this._content;
}
// 日記ページを取得して解析
MixiDiaryEntry.prototype._retrieve = function () {
// ページを読み込む
var html = this._session.fetch("http://mixi.jp/view_diary.pl",
{ id : this._id, owner_id : this._ownerID } );
// 解析
var match = html.match(MixiDiaryEntry._REX_DIARY);
if (match == null) {
throw new MixiError("日記ページを解析できませんでした。");
}
// 日時は Date オブジェクトに
this._date = new Date(match[1], match[2] - 1,
match[3], match[4], match[5]);
// 本文は HTML 含めてそのまま
this._content = match[6];
}
========== end of MixiDiaryEntry.js ==========
MixiDiaryEntry は、view_diary.pl のラッパで、
MixiDiaryIterator#next() が返すオブジェクトだ。
あまり美しい設計ではないが、
Web ページへのアクセスを最小限にするために、
MixiDiaryIterator オブジェクトで取得済みである、
タイトルに関してはコンストラクタで受け取るようにした。
なので、getTitle() だけのアクセスならば、
Web ページへのアクセスは発生しない。
タイトルの一覧等を作るには便利かもしれない。
_retrieve メソッド内では、文字列である html に対して、
match メソッドを実行している。
match は、引数で与えた RegExp オブジェクトの、
exec を実行して返してくれるメソッドだが、
引数で文字列を与えた場合勝手に new RegExp してくれる。
var rex = new RegExp(MixiDiaryEntry._REX_DIARY);
var match = rex.exec(html);
上記と同じだが、少し手数が省けるので使ってみた。
ただ、match に文字列を渡す場合、注意点がある。
まず、RegExp のフラグが指定できないので、
ケース依存(i) の処理はできない。
そして、グローバル(g) のついた正規表現を渡した場合、
一気に文字列に対して全てマッチング(exec)を行い、
一致した部分の文字列をまとめて配列で返す。
このばあい、括弧によるキャプチャ結果は取得できない。
g の場合は exec を実行するのとは結果が異なるのだ。
さて、続いて MixiDiaryIterator#next() を書き換える。
殆ど一緒なので、一部分だけ引用する。
// 日記を取り出す
var entry = this._entries.shift();
// 日記オブジェクトを作成して返す
return new MixiDiaryEntry(
this._session, parseInt(entry[2], 10),
parseInt(entry[3], 10), entry[1]);
entry にはタイトル、日記 ID、著者 ID が格納されている。
それをそのまま MixiDiaryEntry コンストラクタに渡し、
新しく作成したインスタンスを返却しているだけだ。
そして、Main.js のテストコードも一部書き換える。
// 項目を列挙
while (iterator.hasNext()) {
// 項目を取得
var item = iterator.next();
WScript.Echo("================================");
WScript.Echo("日時: " + item.getDate().toLocaleString());
WScript.Echo("タイトル: " + item.getTitle());
WScript.Echo("本文: " + item.getContent());
WScript.Echo("================================");
break; // 全部やると長いのでとりあえず一個
}
さて、実行してみよう。
================================
日時: Monday, August 07, 2006 19:29:00
タイトル: 日記一覧ページを辿る
本文: mixi では日記一覧ページはページャ処理されており、
<br>30 項目ごとに分けて個別のページとなっている。
<br>
(中略)
<br>次は、いよいよ本文の抜き出しだ。
================================
よし、問題なく実行できているようだ。
これで日記の本文が全て取得できるようになった。