2011/02/08

NotebookのScan機能でサイト上の全ページを保存

NILScriptに同梱されている「Notebook.ng」では、手動でページを保存したり自動巡回で新着ページを保存するだけでなく、リンクを辿ってサイト上のページを全て保存させることも可能です。
この機能を利用するには、リンクを辿る基点にしたいページでブックマークレットの「ScanForm」を実行するか、サイドバーの「Scan from Website」からURL未入力のフォームに進んでください。
すると、以下のような画面で使用するプラグインの選択などを行なえます。
巡回登録の場合と同様に、説明を参考に使用するプラグインを選択してください。

「Start」ボタンを押すと、以下のような画面で進捗状況が表示されます。サイトの規模によってはかなりの時間がかかるので注意してください。

Notebook.ngの巡回機能でWebページの更新チェック

NILScriptに同梱の「Notebook.ng」に用意された巡回機能では、RSSリーダーのように新着記事を収集するだけでなく、特定のWebページの内容の変化をチェックすることも可能です。
この機能を利用するには、巡回ルールを「blog/body」や「std/htmlBody」などにして巡回登録してください。
これらのルールでは、子アイテムの抽出は行われませんが、対象URL自体の内容が抽出され、変化があれば保存されます。更新が検出されたページは、Notebookのメイン画面の一覧の上位に表示されます。


ページに更新があると、Notebookのメイン画面の新着ページ一覧の上位に表示されます。この時、一覧項目の下部の「rev.」の部分の番号が更新され、リンクとしてクリックできるようになります。

リビジョンの部分のリンクをクリックすると、このような画面で前のリビジョンとの差分が表示されます。
色の薄い部分が変化の無かった部分、赤みがかった文字色で打ち消し線が引かれているのは削除された箇所、普通の文字の部分が新たに追加された部分です。(追加された文章を読みやすいように、新着部分が普通の配色になっています。)
更に、サイドバーの「This Page」にある「History」のリンクからは、過去のリビジョン一覧や各リビジョンの内容、任意のリビジョン間の差分なども表示できます。

この機能を利用すれば、RSSなどの配信が行われておらず、対応するContentExtractorルールも用意されていないページも、他のサイトと一緒に更新チェックを行なえるでしょう。

なお、この機能で利用されている差分検出の処理は「Diff」というユニットで定義されています。
自作のスクリプトで差分処理を利用したい場合は、「doc」ディレクトリ内の「Diff.txt」の説明を参照してください。

Notebook.ngの巡回機能でブログなどの新着記事を自動収集

NILScriptに同梱されている「Notebook.ng」には、ブログなどの新着記事を自動収集する巡回機能が用意されています。
プラグインで定義したルールに従ってページの本文などを抜き出す「ContentExtractor」機能により、必要な部分だけを保存して、快適に読み進めることが可能です。

Notebookに巡回対象サイトを登録するには、巡回したいサイト上で「AddCrawl」ブックマークレットを実行してください。
すると、以下のような新規巡回項目設定画面が表示されます。



登録対象ページにRSSやAtomのフィードが用意されている場合は、URL欄の下に「rss feed」などとしてリンクが表示されます。このリンクをクリックすれば、フィードURLを対象とした巡回登録画面に移行します。

その下には、インストールされているContentExtractorプラグインとルールの一覧が表示されます。対応URL認識機能によって対応しているとみなされたルールがあると、リストの上位に表示されます。ルール名の下の説明に従って、使用したいルールを選択してください。

ルール名の横の「Test」のリンクからは、そのルールを使用した場合の抽出結果のプレビュー画面に進めます。「blog/rss」などの汎用的なルールを使用する場合は、上手く抽出できるか確認してから登録すると良いでしょう。

Options以下の部分では、高度な巡回オプションを指定できます。一般的なRSS系のルールの場合は、そのままでも問題ありません

「Filters」では、子アイテムに対して除外や改変などのフィルタリングを行うルールを定義できます。この機能はまだ仮のものなので、準備が整い次第別途説明します。

「Interval」は巡回間隔です。たまにしか更新されないページでは大きめの値にすることで、他の巡回をスムーズに出来る場合があります。

「Content Update Check」では、子アイテムごとの更新チェックを行うかどうかと、更新チェック時にHTMLタグ部分を無視するかどうかを指定できます。追記などがほとんどないサイトでは「No」のままでよいでしょう。画像URLのみの更新なども検出したい場合は「Including HTML Tags」を、テキストの更新のみを検出したい場合は「Without Tags」を指定します。

「Children Order」では子アイテムの並び順を指定できます。「No」を指定すると、常に全ての子アイテムがチェックされますが、記事が更新日時順に並んでいることが分かっているサイトでは、適切なオプションを指定する事で、処理を高速化させられます。

「Depth」は、列挙された子ページを更に巡回登録するかどうかのオプションです。子ページの巡回オプションは、その下の「Options for Children」などで指定します。これらは、掲示板のスレッド一覧などを巡回するための機能です。説明部分に「"Depth"を"Crawl Children"にすることで――」のような記載があるルール以外では、設定してもあまり意味がないので「Crawl this URL only」のままにしておいてください。

フォームの一番下の「Save」ボタンを押せば、巡回設定が登録されます。登録された巡回項目の設定変更や削除などは、サイドバーの「All Crawls」で表示される一覧から行なえます。

サイドバーの「Crawl: Disabled」となっている部分の右の「Start」をクリックして「Crawl: Enabled」にしておくと、定期的に巡回が実行されます。収集されたページは、Notebookのメイン画面の最近更新されたページ一覧などで閲覧可能です。

Webページなどを保存して閲覧・検索できる「Notebook.ng」

NILScriptの最近のバージョンから同梱されるようになった「Notebook.ng」は、Webページなどを保存して閲覧・検索できるスクリプトです。
ページの追加はブックマークレットなどから手動で行う他、RSSなどを巡回登録して自動で新着記事を取り込むことも可能です。
NILScriptにはWebページからの本文抽出処理をプラグイン方式で定義できる「ContentExtractor」機構が用意されており、ブログのサイドバーなどの不要部分を除いた本文だけを保存して快適に閲覧できます。更に、検索時にサイドバーのカテゴリ一覧などにマッチして関係のないページがヒットしてしまうという問題も避けられます。

NILScriptは元々このスクリプトを実装することを第一目標として開発を始めたものですが、ようやく主要な機能を実装し仕様も固まってきたので、そろそろ使い方の説明をしたいと思います。

Notebook.ngを使用するには、Notebook.ngをng.exeかngw.exeで実行します。スタートアップなどへの登録は手動で行ってください。
最初に実行すると、データの保存先などを設定するページがブラウザで開かれます。ここでData Directoryに「Portable」を指定すれば、NILScriptのディレクトリをUSBメモリなどで持ち出して複数のPCで利用することも可能です。


初期設定を行うと、以下のようなメイン画面が表示されます。このURLをブラウザのブックマークなどに登録しておいてください。

次に、サイドバーの「Bookmarklets」のリンクからブックマークレット一覧のページに行き、使用したいブックマークレットをブラウザのブックマークに登録します。

基本的なページの保存を行うには、「Scrap」ブックマークレットを使用します。保存したいページを表示した状態で登録したブックマークレットを開くと、範囲選択を行っている場合は選択範囲の内容が、そうでない場合はサイドバーなどの不要部分を自動的に取り除いた部分が、Notebookに新規項目として保存されます。この際、ページに埋め込まれている画像も保存されるため、ページがサーバから削除されてしまっても、支障なく閲覧できます。


ページの保存が行われると、以下のように保存されたページが表示されます。
ここでは、左のサイドバーから「タグ」としてキーワードを関連付けたり、ページの重要度を表す「スコア」を変更したりできます。

サイドバーの検索ボックスに検索ワードを入力すれば、該当するページを検索できます。キーワードの前に「:」を付けると、タグのみを検索対象に出来ます。スペースや「:」を含む語句を検索したい場合は「""」で囲んでください。他のもいくつか検索オプション構文が用意されていますが、詳しくは同梱の「doc\Notebook.txt」を参照してください。

なお、Notebook.ngはまだテスト段階のため、不具合や不便な点が残っていると思われます。見つけた場合は、BBSやTwitterなどでお知らせください。

2011/01/25

IDLファイルからCOMオブジェクト定義を生成して使用する

WindowsがAPIとして用意している機能の中には、COMオブジェクトの形で提供されている物があります。
これらのCOMオブジェクトを利用するために、NILScriptにはCOMユニットが用意されています。
以前のバージョンでは、メソッドの定義を全て自力で記述しなければならないので面倒でしたが、最近の更新で定義を自動化するスクリプトが同梱されるようになったので、手軽に利用できるようになっています
ここでは、COMを利用した処理を行うスクリプトを記述する手順を説明します。

まず、あらかじめWindows SDKをMicrosoftのサイトから入手してインストールしておいてください。
そして、利用したいAPIがCOMオブジェクトとして提供されていることが分かったら、
「C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\」などのディレクトリ内のファイルを全文検索するなどして、どのIDLファイルで定義されているかを調べます。

次に、コマンドプロンプトで以下のようなコマンドラインを実行してください。
ng tool/idlConv "C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\shobjidl.idl" > shobjidl.ng
すると、IDLファイル内の定義文を元に、以下のようなクラス定義が列挙されたスクリプトが生成されます。
var PersistFile=Persist.define("PersistFile","{0000010B-0000-0000-C000-000000000046}",{
    IsDirty:[],
    Load:[
        WideString,        // [in] LPCOLESTR pszFileName
        UInt,              // [in] DWORD dwMode
    ],
    Save:[
        WideString,        // [in, unique] LPCOLESTR pszFileName
        Int,               // [in] BOOL fRemember
    ],
    SaveCompleted:[
        WideString,        // [in, unique] LPCOLESTR pszFileName
    ],
    GetCurFile:[
        Pointer,          // [out] LPOLESTR *ppszFileName
    ]
});
IDLファイルには多くの定義が含まれるので、必要な定義だけを探して自分のスクリプトにコピーしてください。
この時、「.define」の前の派生元クラスの部分が「Unknown」以外になっている場合は、その派生元クラスの定義も見つけてきて派生先クラスの定義より前の部分に記述しておく必要があります。
また、大元の派生元クラスとなる「Unknown」はCOMユニットで定義されているので、以下のような行を一番最初に記述してインポートしておきます。
var {COM,Unknown,BStr}=require('COM');
「COM」や「BStr」もCOMユニットで定義されているクラスで、COMを利用するスクリプトでたまに必要になることがあるので、常に記述するようにしておくといいでしょう。
なお、idlConvによる変換は常に正しく行われるとは限らないので、必ずMSDNのリファレンスなどと照らし合わせて、正しく記述されているか確認してから利用してください。

次に、COMオブジェクトを利用した処理の記述方法を説明します。
以下は、targetPathで指定したファイルを開くショートカットファイルをlnkPathで指定したファイルに保存するという処理の例です。
try{
 var link=ShellLinkW.create();
 var pf=link.toPersistFile();
 link.SetPath(targetPath);
 pf.Save(lnkPath,0);
}finally{
 free(pf,link);
}
「ShellLinkW.create()」は、C++などでの「CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(LPVOID*)&link);」に相当します。
クラスメソッド「create()」によるインスタンス生成を行うためには、idlConvで生成された定義にクラスプロパティ「classID」の定義が付加されている必要があります。もしclassIDの定義が正しく生成されていなかった場合は、各自でIDLファイルなどから「CLSID_~」の定義を探してきて追加しておいてください。

「link.toPersistFile()」は、「link->QueryInterface(IID_IPersistFile, (LPVOID*)&pf)」に相当します。
このメソッドは、「PersistFile」クラスの定義を実行したときに自動的に追加されます。

link.SetPath()とpf.Save()は、COMオブジェクトのメソッド呼び出しです。通常のNILScriptやJavaScriptのメソッドと違い、最初の文字も大文字になっているので注意してください。

最後に、finallyブロック内で「free(pf,link)」を実行して、生成したオブジェクトを解放する必要があります。
これは「if(pf) pf->Release();if(link) link->Release()」に相当します。

このように、最初の定義が多少面倒ですが、処理本体は比較的簡潔に記述できるようになっています。
COMオブジェクトとして提供されているAPIには様々なものがあるので、COMオブジェクトの使用方法を覚えておけば、役に立つことがあるでしょう。