bbsmenu.html の Parse

最初にbbsmenu.htmlをダウンロードする。

ftp http://menu.2ch.net/bbsmenu.html
  1. 「<BR><BR>」で始まっている行がセクションの始まりなので、文字列を取得して現在のセクションに設定する。
  2. 空行でセクションの終わり。
  3. セクションの始まりと終わりの間にでてきたリンクは、「現在のセクション」に所属するものとする。

をそのまま書くと以下のようなスクリプトになる。

open(BBSMENU, '<:encoding(cp932)', 'bbsmenu.html');

my @bbsmenu = ();

while(<BBSMENU>) {
    #セクション開始
    if(/^<BR><BR><B>(.*)<\/B><BR>$/) {
        my $bbs_section = {section_name => $1};

        my @bbs_list = ();
        while(<BBSMENU>) {
            #掲示板へのリンク
            if(/^<A HREF=([^ ]*).*>(.*)<\/A><br>/) {
                push(@bbs_list, {bbs_url => $1, bbs_name => $2});
            } else {
            # 空行のところでセクションは終わり
                last;
            }
        }
        $bbs_section->{children} = \@bbs_list;

        push(@bbsmenu, $bbs_section);
    }
}

セクションが現れるところとそれに続く掲示板へのリンクは以下のようになっており、HTML的な階層構造にはなっていない。idやclassも割り当てていないので、HTML::TreeBuilder を使ってみたりとか、XPathCSSセレクタみたいな modern な parse 手法は却って面倒になる……気がする。

<BR><BR><B>地震</B><BR>
<A HREF=http://headline.2ch.net/bbynamazu/>地震headline</A><br>
<A HREF=http://news21.2ch.net/namazuplus/>地震速報</A><br>
<A HREF=http://live24.2ch.net/eq/>臨時地震</A><br>
<A HREF=http://live23.2ch.net/eqplus/>臨時地震+</A>