C#でスクレイピング

マッシュアップで欠かせない技術の一つにスクレイピングが挙げられる。
WebAPIが提供されていないサイトに対して、HTMLから直接情報を取り出す技術だ。

これには大きく分けて2つの方法がある。
HTMLをテキストとみなし、正規表現で処理する方法と、
HTMLをXHTMLに変換し、そのDOMに対してXPathで処理する方法だ。

こういう分野に強いのはPHPPerlなどの軽量スクリプト言語だろう。
しかしC#使いだってスクレイピングやってみたい。

というわけで、
http://d.hatena.ne.jp/todesking/20061027/1161879777を参考にやってみた。
ちなみにここでやってるのは上記2つの方法のうちの後者。

・・・うまくいかない。
つかTidyマンドクセー!

HTMLをXHTMLに変換したいだけなのに、オプションがありすぎて意味不明です。

もっと手軽なコンバータはないものか。できればマイクロソフト製で。

・・・やっぱりあった。
Microsoft API and Reference Catalog
InfoPath SDKについてるHTMLtoXHTMLというCOMコンポーネントが使えそうです。

簡単にセットアップ手順を説明するとこんな感じ。

  1. http://www.microsoft.com/downloads/details.aspx?FamilyId=351F0616-93AA-4FE8-9238-D702F1BFBAB4&displaylang=enをダウンロードしてインストールする。
  2. 「C:\Program Files\Microsoft Office 2003 Developer Resources\Microsoft Office InfoPath 2003 SDK\Tools」から、次のコマンドを実行する。(COMコンポーネントの登録)「> regsvr32 html2xhtml.dll」
  3. Visual Studioの任意のプロジェクトの「参照設定」→「参照の追加」→「COM」タブから、「HTML2XHTML 1.0 Type Library」を選択して追加。

あとはHTML2XHTMLを使ってHTMLをXHTMLに変換し、XPath等でいじり倒すのみ!

サンプルとしてGoogleで「C#」を検索した結果ページから、
エントリのタイトルを抽出してみる。
今回は3.5らしくLINQtoXMLでやってみよう。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using HTML2XHTMLLib;
using System.Net;
using System.IO;

namespace ScrapingSample
{
    class Program
    {
        static void Main(string[] args)
        {
            WebClient wc    =    new WebClient();
            string html    =    wc.DownloadString("http://www.google.co.jp/search?hl=ja&q=C%23&lr=");

            XHTMLUtilities util    =    new XHTMLUtilities();
            string xhtml    =    util.convertToXHTML(html);

            const string XHTML    =    "{http://www.w3.org/1999/xhtml}";

            XDocument xdoc    =    XDocument.Parse(xhtml);
            var query    =    from a in xdoc.Descendants(XHTML + "a")
                            where a.Attributes("class").FirstOrDefault(atr => atr.Value=="l") != null
                            select a;

            foreach (var item in query)
            {
                Console.WriteLine("Title={0}", item.Value);
            }

            Console.WriteLine("完了しました。");
            Console.Read();

        }
    }
}

出力結果はこんな感じになる。

                                                                                            • -

Title=C# によるプログラミング入門
Title=C Sharp - Wikipedia
Title=Visual C# ホームページ
Title=Visual Studio 2008 Express Editions
Title=@IT:連載 改訂版 C#入門
Title=@IT:特集 私がJavaからC#に乗り換えた10の理由
Title=C#を攻略しよう
Title=C#入門
Title=宇宙仮面の C# プログラミング
Title=C# Tips
完了しました。

                                                                                            • -

LINQのおかげでXML処理は楽勝だぜ!

今後の課題としてはHTML2XHTMLの機能の弱さをなんとかすることだろう。
手軽な分、Tidyなんかよりも融通が効かないところがツライ。