はじめに
WebサイトのHTMLやXMLから、自分に必要な部分を読み取ったり、集めたものを一つに合成して提示したりする技術は、スクレーピング(scraping)と呼ばれています。『SPIDERING HACKS ウェブ情報ラクラク取得テクニック 101選』(オライリー・ジャパン 刊)にはスクレーピングの広範なテクニックが紹介されています。著者も2000年ぐらいから、そのような技術に興味を持って、さまざまなスクリプトを書いてきました(Automated Web Awakening Knowledge, Information and News Gathering Project)。拙著『実践実用Perl』で初めてローカルCGIとして試み、本稿で動作させる環境を明確に定義したデスクトップCGIは、スクレーピングの技術を統合してアプリケーションとしてまとめる技術とも言えます。
『デスクトップCGIでWebとデスクトップを融合する』の第1回は、「Firefox/Apache用AtomリーダーCGIの作成」でした。Webのリソースとデスクトップのリソースの両方にアクセスできるデスクトップCGIを利用すると、デスクトップにあるFirefoxなどのアプリケーションをより有効に活用することができます。
本稿では、引き続き、最近話題のAtomフィードを取り扱います。前回はFirefoxのブックマークからAtomフィードを抽出・リストアップし、「atom2html.cgi」で解析・表示するシステムを作りました。今回は、Atomフィードのフォーマットについて、より正確に理解し、自らAtomフィードを配信できるようになりましょう。具体的には、シフトJIS文字コードで書かれたHTMLサイトの記事を、UTF-8文字コードのAtomフィード(XML)に変換して配信するデスクトップCGIを作成します。HTMLからXMLに変換することによって、XMLとHTMLの違いについても理解を深めることができるでしょう。
本稿で作成するもう一つのデスクトップCGIは、ファイル名のフルパスをパラメータとして与えると、関連付けを利用してアプリケーションを起動する「start.cgi」です。このCGIは簡単なものですが、デスクトップにWebブラウザからアクセスするための仕組みとして、今後重要になると考えています。
また、デスクトップCGIのセキュリティについても最初に言及しておきます。デスクトップCGIとWebで使用する通常のCGIはセキュリティ的に区別して考えておく必要があります。
Perlとそのモジュールの詳細については特に説明しませんので、第1回に紹介した書籍や参考資料などを参考にしてください。初めて登場するNet::FTPモジュールについては、今回の参考資料にリンクを置いておきます。
対象読者
Perl、CGI、テキストエディタ、HTML、HTTPサーバー(特にApache)、Webブラウザ、文字コード、コマンドプロンプトや環境変数などのWindowsのシステムについての基礎的な知識を持ち、かつ、インターネットからソフトウェアをダウンロードして、インストールできるレベルの方。
必要な環境
Windows環境を前提にまとめたものを更新して再掲します。違いはFirefoxのバージョンが新しくなったことだけです。初めて読まれる方は、インストール方法については、第1回の「必要な環境」の項も参照ください。
- ActivePerl 5.8.8.817 (5.8.6以降)
- TeraPad(ToClip for Windows)などのUTF-8が取り扱えるテキストエディタ
- UTF-8の表示ができるコンソール ck - terminal emulator
- ckを使うためのCygwin
- Apache HTTP サーバー 2.0 (実際に使用しているのは、2.054: Welcome! - The Apache Software Foundation)
- Firefox 1.5.0.4 (Firefox - Web の再発見)
デスクトップCGIのセキュリティ
デスクトップCGIは、ユーザー自身がデスクトップで使用するCGIであり、ファイアーウォールで守られた、善意の人たちのみが接続している、例えば家庭や仕事場にあるLAN環境の特定の個人が使用するパーソナルコンピュータ(以下、PCと表記)で使用することを想定しています。従って、この想定下で使用している限り、セキュリティ上の問題は生じないと考えています。しかし、家庭での使用はともかく、不特定多数が接続する可能性がある仕事場などでは、場合によっては他のPCからのアクセスを受ける危険性がまったくないとは言えないかもしれません。デスクトップCGIの安全サイドの運用を実現するために、本稿第1回のApacheのインストールを改訂し、更新しましたので、ここで簡単に説明しておきます。
また、Webで使うCGIなどのアプリケーションについて、XSS(クロスサイトスクリプティング)脆弱性という言葉を目や耳にした方も多いと思いますが、スクリプトを書く際にデータ入力のチェックなど、注意を払う点があります。本稿のデスクトップCGIはそのような点については考慮していませんので、Webで応用する際には、XSS脆弱性などの問題が生じる可能性があることに留意して、調査検討し、必要と考えられる処置を取っていただくようにお願いいたします。XSS対策については、『@IT:クロスサイトスクリプティング対策の基本』の記事が参考になるでしょう。
Apache のhttpd.confのデスクトップCGIのセキュリティを考慮した設定
デスクトップCGIのセキュリティを確保することは、デスクトップCGIが動作するHTTPサーバーに他のPCからのアクセスができない設定に変更することによって達成できます。「DocumentRoot」と「cgi-bin」のApacheの「httpd.conf」のデフォルトの設定では、すべてのIPアドレスからアクセスを許可する設定になっています。「httpd.conf」の次の2箇所の<Directory>
ブロックディレクティブにその設定があります。<Directory>
ブロックディレクティブは、ディレクティブ(命令、あるいはコマンドという意味です)の適用を特定のディレクトリの範囲に限定するためにあります。
<Directory "C:/Program Files/Apache Group/Apache2/htdocs"> Options Indexes FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory>
<Directory "C:/Program Files/Apache Group/Apache2/cgi-bin"> AllowOverride None Options None Order allow,deny Allow from all </Directory>
問題のアクセスを許可する部分は2箇所とも、「Order allow,deny」と「Allow from all」の2行です。「Allow from all」はすべてのIPアドレスからのアクセスを許可する設定です。「Order allow,deny」は、allow(許可)してからdeny(禁止)するという順序を指定していますが、denyディレクティブは存在しませんから、「Allow from all」の許可のみが行われます。
<Directory>
ディレクティブを次のように指定すると、localhostすなわちサーバーマシンのみからのアクセスが許可されるようになります。
<Directory ディレクトリ> ・・・・・ Deny from all Allow from 127.0.0.1 Order deny,allow </Directory>
まず、Deny from all
ですべてのIPアドレスからのアクセスを禁止します。それからAllow from 127.0.0.1
で、localhostからのアクセスを許可します。Order deny,allow
のdeny
とallow
の順序が重要です。逆だとすべてのIPアドレスからのアクセスが禁止されてしまいます。127.0.0.1
はlocalhost
と記述しても同じです。IPアドレスかホスト名を記述します。
デスクトップCGIが動作するサーバーマシン以外に特定のマシンからアクセスできるように追加したい場合には、127.0.0.1
の後に半角空白に続けて、該当のIPアドレスを記述します。
Apache HTTP サーバーのディレクティブについては、Apache HTTP サーバ バージョン 2.0 ドキュメント - Apache HTTP サーバのcore - Apache HTTP サーバに詳しいので、他のディレクティブの意味などについて知りたい場合には参照してください。
Atomフィードフォーマットの詳細
Atomフィードの要素と属性
CGIを作成する前に、Atomフィードのフォーマット(バージョン1.0)の詳細を、要素と属性の一覧表でまとめておきましょう。『The Atom Syndication Format』を元にして作成しました。
feed
コンテナ要素は、feed
を特徴付ける他の要素と共にentry
コンテナ要素を含み、entry
コンテナ要素は記事を構成する要素を含むという入れ子構造になっています。Personコンストラクトであるauthor
要素とcontributor
要素は、いずれもfeed
コンテナ要素とentry
コンテナ要素に含めることができますが、name
要素などの子要素が入れ子になっています。
要素には、link
要素やcategory
要素のように属性だけで値を持つものや、title
要素やname
要素のように属性を持たずに値だけを持つもの、generator
要素のように終了タグの間の値と属性値の両方を持つものがあります。
- 表1 Atom配信フォーマット要素・属性一覧(別のウィンドウで開きます)
entryコンテナ要素のpublished要素とupdated要素
Atom配信フォーマットのバージョン0.3は現在でも、Google系のBloggerのAtom配信に使われています。バージョン0.3では、記事の作成日付はissued
要素に格納され、記事の更新日付はmodified
要素に格納されています。Atom配信フォーマット(RFC4287)を調べると、バージョン1.0でこれらに対応する要素は、定義からそれぞれpublished
要素とupdated
要素と考えられます。
FirefoxのフィードリーダーのSageやWindows Vista Beta 2のインターネットエクスプローラなどではフィードの日付には、バージョン0.3の場合はmodified
要素、バージョン1.0の場合はupdated
要素を使います。
ここで問題が生ずるのが、記事を作成した時点ではupdated
要素が論理上は存在しないことです。Atom配信フォーマット(RFC4287)では、entry
コンテナ要素にupdated
要素は必須ですが、published
要素は一つ以上含んではならないのであって、必須ではありません。本来ならAtomリーダーが、updated
要素がなければ、published
要素を表示する仕組みを持てば、published
要素を必須とし、entry更新後は、updated
要素を必須とすることによって問題はなくなります。
しかし、現実問題として、updated
要素が必須という規則があるためか、一般的なAtomリーダーではpublished
要素だけでは、updated
要素を持たない新規記事の日付が表示されません。従って、本稿の「rn2atom.cgi」では、updated
要素を持たない新規記事では、updated
要素はpublished
要素と等しい値を置くことにしています。
配信に必須のAtom配信要素
author要素
author
要素は著者情報ですが、子要素としてname
要素が必須です。feed
コンテナ要素とentry
コンテナ要素においても同じです。
id要素
id
要素には後述のIRIを用いますが、id
要素の比較は、文字列の比較として行われます。id
要素にURLを用いる場合、URLの記述においては大文字小文字の区別がないことや%7Eなどのエスケープ文字列の使用の有無などが、実際的な文字列の差異となって現れることに注意する必要があります。feed
コンテナ要素とentry
コンテナ要素においても同じです。
link要素
feed
コンテナ要素の場合は、rel
属性の値をself
として、href
にAtom配信のファイルのURLを設定します。entry
コンテナ要素の場合は、rel
属性の値をalternate
として、href
に元記事に対応するURLを設定します。
title要素
feed
コンテナ要素の場合は、Atom配信の表題を設定します。entry
コンテナ要素の場合は、記事の表題を設定します。
updated要素
feed
コンテナ要素の場合は、Atom配信の更新日時を設定します。entry
コンテナ要素の場合は、記事の更新日時を設定します。
content要素
entry
コンテナ要素には、記事の内容をcontent
要素として格納できます。text形式、html形式、xhtml形式などが使えますが、XMLであるAtomフィードに矛盾なく格納するためには、xhtml
形式が適しています。本稿では、HTMLで書かれている記事をxhtml
形式に変換して格納します。
IRI
表のデータ型にIRIという値がありますが、Internationalized Resource Identifiers (IRIs)に定義されています。現時点では、URI(Uniform Resource Identifier (URI): Generic Syntax)と同義で使っても差し支えありません。URIがUS-ASCIIで記述されるのに対して、IRIはUnicodeで記述されますので、実質的にIRIはURIを補完するものです。なぜ、IRIが提案されているかは、An Introduction to Multilingual Web Addressesを参照してください。将来は、URIをUnicodeを使って多国語で記述できるようになるでしょう。