Rawler Framework C#用、webスクレイピングとテキスト処理のためのフレームワークを作ったよ。その1

webからこの情報がほしいとかいう需要はそこそこあるのだと思うのだけど、それに対してプログラミングで取ってこればいいというのは、プログラムのできる人の言うことであって、プログラムのできない人にそれを言うのは酷である。確かに、今は、ライブラりが整備されているので、わりとちょこちょこググれば、自分の使っているプログラミング言語でのやり方はあっさりわかる。でも、プログラミングができない人に、自分のほしいwebページの情報を取るために、プログラミング言語の習得から始めるのは、やりたいこととやれることの距離が遠すぎる。
また、実際にプログラミングを組む側でも、webから適切な情報を取ってくるという処理は、かなりだるい。そもそもデザインが変わると取れなくなってしまうし、やることが基本的に繰り返しで、そのパラメータとかをいちいちHTMLのソースと見比べながら、ちょこちょこ変えていくのだが 結局はそれだけなので、誰かに任せたくなる。コードの再利用性を高め、クロール部分とデータに書き込むロジックの分離を図り、いわゆるWEBサイトの開発などで言われる、デザインとロジックの分離と同等のことを達成したい。

そんなわけで、わりと気持ち初心者から、上級者にも使える感じで「Rawler Framework」を作ってみた。

ダウンロードはここhttp://web.sfc.keio.ac.jp/~kiichi/wiki/index.php?Rawler

基本的にこのフレームワークXAMLのみで記述できる。XAMLとは、XMLマイクロソフトの拡張で、C#でのオブジェクトの状態と関係をXML形式で書けるものである。テキストであるが故、コピペの使用感が素晴らしい。実際に、WPFでは画面のデザインに使われている。(画面のデザインもオブジェクトの状態と関係の記述だ)WPFでは、XAML部分で画面のデザイン、そのXAMLとくっついた形で、コードビハインドでロジックを記述できるのと同様に、Rawlerもコードビハインドに対応していて、イベントパンドラを追加したりして、拡張性を確保している。とはいっても、XAMLのみでも動き、サイトにあるZIPファイルの中に含まれているEXEを起動してできる、ツールにXAMLをコピペするとそれだけで動く。なんちゃってインタープリターである。C#コンパイルしないとだめな言語なのに!

まぁ、Rawlerを記述するためには、VS.NetのXAML編集機能を使うとインテリセンスが働くので圧倒的に書きやすい。記述制約が強いため、作る時は、VS.Netを使うといい。手書きは非奨励。

Rawlerの一番シンプルな例はこれである。

<Data Comment="" 
      xmlns="clr-namespace:Rawler.Tool;assembly=Rawler"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      >
    <Page Url="http://d.hatena.ne.jp/kiichi55/">
        <Link>
            <Report></Report>
        </Link>
    </Page>
</Data>

これをツールの上のテキストボックスに入れて、実行ボタンを押すと、http://d.hatena.ne.jp/kiichi55/ からページをダウンロードして、そのページにあるリンクをすべて下のテキストボックスに書き出す。

解説すると、 にある記述は、おまじないだ。今のところ、特に気にしないでくれ。
次のでUrlを指定すると指定した所から取ってくる。で囲まれたところには、そのダウンロードしたHTMLが入っていると思っていい。そのHTMLから、でリンクを判別し、さらに子に見つかった個数分のURLを渡す。そして、でそのURLを出力を繰り返す。

Rawlerでは、親から子へテキストを流していくという仕組みを取っており、親は子を複数持てるので、同じテキストに対して複数の処理をすることができる。そういうわけで、いくつかの命令を使って、テキストの範囲を狭めながら取っていくものというのが基本である。
ここでの売りは、変数の排除である。プログラミングを組む時、面倒なのはいちいち一時変数の名前を考えないといけないのだが、これの場合、考えなくてすむし、ツリー構造で示されるため、変数の変化の過程がわかりやすい。(このような構造だからこそ、二つ以上の動的な変数の扱いは難しくなっているのだが・・・)
余計なことはさておき、webスクレイピングのために作ったものなので、それ用に便利な機能がある。それはNextPage機能だ。これは、に次に読むべきURLを渡してがそのURLをダウンロードしてまた同じ手順を繰り返すのだ。これは同じ形式になっているサイトでの次へボタンがあるサイトで威力を発揮する。

こんな感じだ。実行して終了するまで少し待つ。

<Data Comment="" 
      xmlns="clr-namespace:Rawler.Tool;assembly=Rawler"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      >
    <Page Url="http://d.hatena.ne.jp/kiichi55/">
        <Link>
            <Report></Report>
        </Link>
        <Link TagFilter="prev" IsSingle="True">
            <NextPage></NextPage>
        </Link></span>
    </Page>
</Data>


LinkでのTagFilterを指定することでTagの中に指定した文字列を含むLinkだけを抽出する。次へに使うだけなので、IsSingleで一つだけを出力させる。これではてなのページならどんどんページ送りがなされる。でも出力には、サイドバーなどにあるいらないURLが出てきてしまう。
当然、ページ送りをするのだから、記事だけの情報がほしいだろう。次のように改造する。

<Data Comment="" 
      xmlns="clr-namespace:Rawler.Tool;assembly=Rawler"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      >
    <Page Url="http://d.hatena.ne.jp/kiichi55/">
        <TagExtraction Tag="div" ClassName="section">
            <Link>
                <Report></Report>
            </Link>
        </TagExtraction>
        <Link TagFilter="prev" IsSingle="True">
            <NextPage></NextPage>
        </Link>
    </Page>
</Data>

TagExtractionはTagで指定したタグを複数取ってくる。ClassNameを指定することとで、その中で、タグのClass名が"section"であるものを探してくる。そうするとはてなの場合、記事部分の取ってこれる(他のサイトの場合自分でHTMLの法則を見破ってくれ!)ので、記事部分にあるURLが書きだされる。

はシンプルなログ吐き機能でしかない。ほしいのは構造化されたデータである。そのための機構はちゃんと用意してある。の三つだ。はデータを貯めるところである。必ず上流になくてはならない。に属性(エクセルで言う列名だ)付きで書き込みに行く。そして、でそこまで貯めたのを一行分として次の行に進む。このようにして、構造化されたデータを貯めていく。
もし、を指定し忘れると、行送りはなされず、属性にリストとして値が溜まっていく。デフォルト設定では、属性に対して追加するのみで値を書きかえることはない。

リンクの中身とURLという二つの列をもつデータの取得。実行ボタンを押して完了を待って、ViewDataを押すと見れる。

<Data Comment="" 
      xmlns="clr-namespace:Rawler.Tool;assembly=Rawler"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      >
    <Page Url="http://d.hatena.ne.jp/kiichi55/">
        <TagExtraction Tag="div" ClassName="section">
            <Link VisbleType="Tag">
                <Link VisbleType="Label">
                    <DataWrite Attribute="label"></DataWrite>
                </Link>
                <Link VisbleType="Url">
                    <DataWrite Attribute="url"></DataWrite>
                </Link>
                <NextDataRow></NextDataRow>
            </Link>
        </TagExtraction>
        <Link TagFilter="prev" IsSingle="True">
            <NextPage></NextPage>
        </Link>
    </Page>
</Data>

はVisbleTypeを指定することで、そのタグそのもの、タグで挟まれたところ、URL部分をそれぞれ取得できる。このようにすることで、URLと中身のペアが取れる。はてななので、キーワードとの組み合わせがいっぱい出る。
が発動した時に発生するイベント(Commited)があるので、逐次的にデータベースに入れるなどの処理もできるようになっている。

あと書き忘れた重要な売りは、ページの連続読み込みに対応していること。

<Data Comment="" 
      xmlns="clr-namespace:Rawler.Tool;assembly=Rawler"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      >
    <Page Url="http://d.hatena.ne.jp/kiichi55/">
        <Link >
      <Page>
              処理・・・・
            </Page>
        </Link>
    </Page>
</Data>

という感じで書くと、読み込んだページにあるURLからさらにページに飛んでいくことができる。はURLが空の時、親にある文字列をURLとして読み込みにいくためだ。このような感じで複数のページに飛んでデータを取得するという処理もこんな感じに簡単に書ける。


まぁ、こんな感じに使えるようになっているフレームワークある。いろいろと他にも便利機能があって、これだけでかなり完結できるはず。
その説明は、力尽きたのでまた今度。