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なんかよりも融通が効かないところがツライ。

GoogleCalendarAPI + LinqToXMLで休日を取得する方法

があまりにも簡単すぎて思わず吹き出した。

LinqToXMLでGoogleCalendarAPIにアクセスし、
2007年1月1日から2008年1月1日までの休日をピックアップしてみる。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;

namespace Sample
{
    class Program
    {
        static void Main(string[] args)
        {
            string URL  =   
"http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full?start-min=2007-01-01&start-max=2008-01-01";
            string ATOM =   "{http://www.w3.org/2005/Atom}";
            string GOOGLE   =   "{http://schemas.google.com/g/2005}";

            XDocument doc    =   XDocument.Load(URL);

            var query    =   from entry in doc.Root.Elements(ATOM + "entry")
                            from when in entry.Elements(GOOGLE + "when")
                            orderby when.Attribute("startTime").Value
                            select new { 
                                Title=entry.Element(ATOM + "title").Value, 
                                Date=when.Attribute("startTime").Value 
                            };

            foreach (var item in query) { Console.WriteLine("{0}は{1}", item.Date, item.Title); }

            Console.Read();
        }
    }
}

実行結果はこんな感じ。

2007-01-01は元日
2007-01-08は成人の日
2007-02-11は建国記念の日
2007-02-12は振替休日
2007-03-21は春分の日
2007-04-29はみどりの日
2007-04-30は振替休日
2007-05-03憲法記念日
2007-05-04は国民の休日
2007-05-05はこどもの日
2007-07-16は海の日
2007-09-17は敬老の日
2007-09-23は秋分の日
2007-09-24は振替休日
2007-10-08は体育の日
2007-11-03は文化の日
2007-11-23は勤労感謝の日
2007-12-23は天皇誕生日
2007-12-24は振替休日

かつてRSSフィードを取得するRSS.NETとかあったけど、
LinqToXMLがあれば
XMLで公開されているWeb上のリソースを取得するためのライブラリなんて
もういらなくね?

楽すぎる〜(^0_0^)

「メソッド」の語源

一昔前に流行った「高橋メソッド」の
「メソッド」ですが、英語の語源はギリシャ語の
「メタ・ホドス」でして、
英語で直訳すると「on the load」ってところでしょうか。
つまり「道の上を」進むように、ある規則性に従って物事を進めることなんですね。

なんでこんなことを言い出すかというと、
メタミドホス」と「メタ・ホドス」似てるなぁと思って。
すんません、ただそれだけ。


ちなみに、メタミドホスの語源は
Meth(メタ)=メチルmethyl (-CH3)+
amido(アミド)= amides(-NH2)+
phos(ホス)=phosphoric acid(リン酸)
だそうです。
http://blog.livedoor.jp/aroma_master/archives/51291701.html

日経平均13629円に回復

ちょっと上がってきました。。。
オイラが買った株が利益を出すまではまだまだですが、
それでもやはりうれしいものです。
来年か再来年には売れるぐらいまでに
回復してるかな?

お金は銀行に預けるな   金融リテラシーの基本と実践 (光文社新書)

お金は銀行に預けるな 金融リテラシーの基本と実践 (光文社新書)

この本を読んで投資信託もアクティブからインデックスに
シフトしようかなと思った。
一ヶ月前の日経のコラムにも、
長期的に見た場合アクティブ型の投信が
インデックス型を上回ることはなかなか難しいとあったし。
そうなると諸費用の安いインデックスが断然有利ですよね。
年利4、5%ぐらいで上等、10%は良すぎ
という目標設定の目安にも納得。
オススメの本です。

LINQいい感じです。

Visual Studio 2005で開発したWebサイトをVisual Studio 2008に移行して
.NET Framework3.5の恩恵を受けています。

当然LINQも使うぜ。というか非常に便利です。
特に便利だと感じたのはADO.NETと相性の良さです。
今まではテーブル結合後のデータを取得するために
データセットにテーブルアダプターの定義を増やしていましたが、
LINQだと単一テーブルのデータアダプターで取得した
テーブル同士を結合できるので、
ちょっと名称を取りたい、なんてときに便利。

Application Architecture for .NETの概要

連載:アプリケーション・アーキテクチャ設計入門 - @ITより抜粋。
2003年の記事だが内容は今も有効。

ユーザー・インターフェイスコンポーネント

データの入力時には以下の処理をする。

    • データを取得する
    • ツールやガイドでデータの登録を助ける
    • ユーザーの操作を解釈して、Controllerを呼び出す
    • Controllerは、ユーザー・プロセスを開始したりユーザー・プロセスの状態を変えたりすることで、ユーザー・インターフェイスコンポーネントの表示内容を変更する
    • 入力可能なデータの型を制限する
    • 入力されたデータを検証する
    • 入力されたデータを、その後に控えるコンポーネントに都合が良いようにマップしたり変形したりする

データの出力時には以下の処理をする。

    • ビジネス・コンポーネントまたはデータアクセス・ロジック・コンポーネントのデータを取得して表示する
    • 表示フォーマットを決める
    • 表示データをローカライズする(リソース文字列などによる)
    • ビジネス・エンティティに関係するデータを表示する。ビジネス・エンティティの実装がADO.NETのDataSet型を使用していれば楽だが、独自のビジネス・エンティティ・コンポーネントならば追加のコードが必要である
    • アプリケーションのステータス情報を表示する
    • ユーザー・インターフェイスの外観を、ユーザー設定や使用デバイスに応じてカスタマイズする
  • 推奨

Windowsアプリケーションの場合

    • 同時に開かれるフォーム間でデータを同期するためには、データ連結を使う
    • 画面遷移はコードに直接記述せずに、ユーザー・プロセス・コンポーネントを利用する
    • フォームでも例外をキャッチする
    • サーバのコンポーネントを呼び出す前に、ユーザーの入力を検証して結果をユーザーに見せる
    • カスタム・ユーザー・コントロールインターフェイス(プロパティやメソッド)は必要最小限だけを公開する
    • イベント・ハンドラに直接Controller機能を実装しないで、最低限メソッドを別にする

Webアプリケーションの場合

    • カスタムエラー・ページを用意し、global.asaxでアプリケーションのエラーを処理する
    • データの検証はクライアント側だけではなく、ほかのページに遷移する前にサーバ側でも行う
    • カスタム・ユーザー・コントロールインターフェイス(プロパティやメソッド)は必要最小限だけを公開する
    • ページ固有の状態を保持するためにはビューステート(ページのViewStateプロパティ)を使う
    • ページのリダイレクトはController機能が直接するのでなく、必ずユーザー・プロセス・コンポーネントで行う
    • イベント・ハンドラに直接Controller機能を実装しないで、最低限メソッドを別にする

モバイルアプリケーションの場合

    • どちらの場合も基本的にデスクトップPC向けと同じだが、モバイル・デバイスの場合は特に入力データの検証に注意を要する。Webであれば、クライアント側での検証には多くを期待できないし、スマート・デバイスであれば、Visual Studio .NETの「スマート・デバイス拡張」には、検証コントロールが含まれていないためである。

(Office製品をUIとする)ドキュメントの場合

    • ドキュメント・ベースのユーザー・インターフェイスにおいても、入力データの検証には注意が必要である。データ型を限定するだけでなく、データをチェックしてエラーを表示する機能を実装する場合も多いだろう。

ユーザー・プロセス・コンポーネント

  • 特徴
    • トランザクションを開始しない。トランザクションに参加したり投票したりもしない
    • ビジネス・ロジックに関連する内部データとユーザー・プロセスの内部状態を保持し、必要に応じて永続化する
    • 個々のステップとして遷移する画面は、コードに直接書くか、構成ファイルなどのメタデータから動的に取得する
    • 内部データを初期化させるために、ビジネス・コンポーネントやデータ・アクセス・ロジック・コンポーネントを呼び出してもよい
    • メニューを管理するカスタム・ユーティリティ・コンポーネントから開始されてもよい
  • 役割
    • ユーザー・インターフェイスの構成要素を、データフローや制御ロジックを変えずにインタラクション(ユーザーとのやりとり)の順序制御に対応付ける
    • ユーザー・インターフェイスのセッションを、関係するユーザー・プロセスに対応付ける
    • インタラクションの概念的な順序を実装やデバイスから独立させる
    • 例外がユーザー・プロセスに悪影響を及ぼさないようにする
    • ユーザー・プロセスがどのように状態を変えていったのかを保持する
    • ユーザー・プロセスによって変更されたビジネス関連データを保持する
    • ユーザー・プロセスに中断と再開の機能を加える
    • ユーザー・プロセスが完了するときに、ビジネス・コンポーネントを呼び出す
  • 推奨
    • 設計時に、ユーザー・プロセスをコンポーネントとして分離すべきかどうかを検討する。ユーザー・プロセス・コンポーネントの設計は簡単な作業ではない
    • ユーザー・プロセス・コンポーネントシリアライズ可能にして、ビジネス・プロセスとは別個に永続化できるようにする
    • ユーザー・プロセスをどこに保存するのかを検討する。クライアントがオフラインで動作するのか、障害が起きた場合にユーザー・プロセスを復元すべきなのか、別のコンピュータでプロセスを再開することがあるのか、などが判断基準となる
    • ユーザー・プロセス・コンポーネントで例外をとらえ、ユーザー・インターフェイスに渡す

書きかけ・・・

読みかけ

最近読んでて面白い。
連載:アプリケーション・アーキテクチャ設計入門 - @IT

.NETを使っていていつもこんなことを感じます。

便利な機能やコンポーネントがたくさんある。
でもこれらをどうやって使えばいいのかよくわからない。

マイクロソフトが推奨するアーキテクチャの指針を押さえておくと
.NETと親和性の高い設計ができるように感じます。

記事は古いですが今も有効ってことで。

あとSQLServerのReportingServiceも使ってみよう。