Webベースのデータ・マイニング

HTML、XML、Javaを使用した自動データ抽出

Webが、これまでで最も豊富で、最も密度の濃い情報源であることは疑いのない事実ですが、その構造のため、情報を体系的に利用することは大変です。本稿で紹介する方法やツールによって、Webの技術をよく理解している開発者は、迅速にかつ簡単に必要な情報をWebから取り出すことが出来るようになるでしょう。

Jussi Myllymaki, Researcher, IBM

Jared Jackson氏は、2000年5月のHarvey Mudd Collegeの卒業後、IBM Almaden Research Centerに勤務しています。Jared氏は、スタンフォード大学のコンピュータサイエンス学部で大学院の研究にも取り組んでいるところです。



Jared Jackson, Researcher, IBM

Jared JacksonWebが、これまでで最も豊富で、最も密度の濃い情報源であることは疑いのない事実ですが、その構造のため、情報を体系的に利用することは大変です。本稿で紹介する方法やツールによって、Webの技術をよく理解している開発者は、迅速にかつ簡単に必要な情報をWebから取り出すことが出来るようになるでしょう。



2001年 6月 01日

この情報時代におけるWebの急成長により、多種多様な情報がいたるところに分散されるようになりました。残念ながら、この情報を伝達するときに主に使われるHTMLは、人間の読者に情報を提示するには便利な方法ですが、データ・ドリブンのサービスやアプリケーションの関連情報を自動的に取り出すには、構造的に問題があります。

この問題を解決するために、これまでもさまざまなアプローチが取られてきました。そのほとんどは専用の照会言語を用いて、HTMLページのセクションを、Webページからとってきた情報をデータベースに入れるためのコード(インデクス)にマップするというものです。これらのアプローチにもメリットはありますが、実用的でない理由が2つあります。1つは、他の場面では役に立たない照会言語の学習に時間をかけなければならないこと、もう1つは、ターゲットとするWebページに単純な変更 (必然的に発生します) が加えられた場合でも、それを反映できないことです。

本稿では、Webの標準テクノロジーであるHTML、XML、Javaを使って、Webベースのデータ・マイニング方法を開発します。この方法は、他の専用のソリューションと比べても、より強力ではないにしろ、おなじくらい強力で、Webのテクノロジーをすでによく知っていれば、それほど時間をかけなくてもしっかりした結果が得られます。おまけとして、データ抽出を開始する場合に必要となるコードも記事の中で紹介します。

HTML: 祝福と呪い

HTMLは、プログラムの観点から見ると使いにくい媒体です。Webページのコンテンツの大半は、データ・ドリブンのシステムには関係のないフォーマットを記述したもので、ドキュメントの構造は、動的バナーの追加などのサーバー側のスクリプトにより、ページに接続するたびに変化している可能性があります。また、最新のWebブラウザーではHTMLの記述が完全ではなくても構文解析されるため、すべてのWebページの大部分が適切にフォーマットされておらず、それにより問題は一層複雑になっています。

こうした問題はありますが、データ・マイナーの点からすれば、HTMLには都合のよい面があります。興味深いデータはしばしば<table>タグや<div>タグで他と切り離されているので、抽出プロセスはそのドキュメントのごく一部のみを対象にすればいいのです。クライアント側のスクリプトがない場合に、ドロップダウン・メニューなどのデータ・リストを定義する方法は一つしかありません。のようなHTMLの性質によって、一度データを操作可能なフォーマットにしておけばデータ抽出のみに注力できるのです。


バックグラウンドのテクノロジー

ここで説明するデータ・マイニング・テクノロジーの鍵は、既存のWebページをXML、あるいはおそらくもっと適切なXHTMLに変換し、数多くあるツールのいくつかを使って、XML形式で構造化されたデータを使って、関連のあるデータを取得することです。

うれしいことに、HTMLページの釣り合っていないデザインの多くを修正できるソリューションがあります。Tidyは、複数のプログラミング言語に対応しているライブラリーで、HTMLドキュメントでよくある間違いを修正し、適切にフォーマットされた同等のドキュメントを生成する、フリーウェアです。Tidyでは、XMLのサブセットであるXHTMLでこれらのドキュメントを記述することもできます(参考文献を参照)。

ここで紹介するコード例は、Javaで作成したものなので、コンパイルして実行するときに、Tidyのjarファイルをシステムのclasspath に入れる必要があります。また、ApacheプロジェクトのXercesとXalanを使って、XMLライブラリーを利用できるようにすることも必要です。Apacheプロジェクトのこれらの2つのライブラリーは、IBM提供のコードに基づき、それぞれXML構文解析とXSL変換を行います。これらの3つのライブラリーはそれぞれ、Webで無料公開されています。本稿最後の参考文献を参照してください。例では、Javaプログラミング言語、XML、XSLの変換の知識が役立ちます。これらのテクノロジーについても、参考文献を参照してください。


アプローチの概要と例の紹介

例を使って、データ抽出方法を説明します。過去数ヶ月間にわたって1日のさまざまな時間におけるワシントン州シアトルの気温と湿度を追跡するとします。この種のレポートを作成する市販のソフトウェアの中にニーズを満たすものがなくても、多くのパブリックのWebサイトの中からこの情報を取り出すことは可能でしょう。

図1 に、抽出プロセスの概要を示します。既存のデータ・セットに取り込むことができるデータ・セットが作成されるまで、Webページを取ってきては、処理します。

図1. 抽出プロセスの概要
図1. 抽出プロセスの概要

いくつかの短いステップで、必要な情報だけを収集する信頼性の高いシステムを作ります。下にそのプロセスの概要のリストを示します。このプロセスは図1に示されています。

  1. データ・ソースを識別し、XHTMLにマップします。
  2. データ内で参照点を探します。
  3. データをXMLにマップします。
  4. 結果をマージし、データを処理します。

次に、これらのステップを詳しく説明し、各ステップの実行に必要なコードを紹介します。


ソース情報をXHTMLとして取得する

データを抽出するためには、もちろん、そのデータを探す場所が分かっていなければなりません。たいていの場合、ソースは言うまでもなく明らかです。developerWorksからURLや記事のタイトルを集めて保持したい場合は、ターゲットとして http://www.ibm.com/jp/developerWorks を使用します。天気の場合は、選択できるソースがいくつかあります。この例ではYahoo! Weatherを使いますが、他のサイトでも同様です。ここでは、URL http://weather.yahoo.com/forecast/Seattle_WA_US_f.htmlでデータを追跡することにします。 図2 に、このページのスクリーンショットを示します。

図2. ワシントン州シアトルのYahoo! Weather Webページ
図2. ワシントン州シアトルのYahoo! Weather Webページ

ソースを考える場合は、次のことを念頭に置くことが大切です。

  • ソースは、信頼できるネットワーク接続で信頼できるデータを提供するか。
  • 1週間後、1ヶ月後、あるいは1年後にソースが同じ場所に存在するか。
  • ソースのレイアウト構造がどれくらい安定しているか。

われわれが求めているのは、動的な環境でも機能する確実なソリューションですが、最も信頼性が高く安定したソースを利用し、そこからデータを抽出すれば、作業は一番簡単です。

ソースが決まったら、抽出プロセスの最初のステップはHTMLからXMLへのデータの変換です。このようなXML関連のタスクを実行するには、静的なhelper関数から構成された XMLHelper というJavaクラスを作成します。このクラスの完全なソースについては、XMLHelper.javaXMLHelperException.java を参照してください。このクラスのメソッドは、話を進めながら説明していきます。

Tidyライブラリーの機能を使用して、メソッドXMLHelper.tidyHTML() で変換を実行します。このメソッドは、パラメーターとしてURLを受け取り、結果としてXMLドキュメントを返します。このようなXML関連のメソッドを使用する場合は、例外の発生に注意してください。この場合のコードを リスト1 に示します。このコードの出力は図3 のようになります。これは、WeatherページをXMLで表しているMicrosoftのInternet Explorer XMLビューアーのショットです。

図3. XHTMLに変換されたYahoo! Weather Webページ
図3. XHTMLに変換されたYahoo! Weather Webページ

データの参照点を探す

Webページにしろ、ソースのXHTMLビューにしろ、情報の大部分はわたしたちにまったく関係ないものであることに注意しましょう。次のタスクは、XMLツリー内で、無関係の情報に煩わされることなくデータを抽出できる特定の領域を見つけ出すことです。抽出がもっと複雑になると、1つのページでこれらの領域を複数探さなければならない場合もあります。

通常は、最初にWebページを調べてからXMLを処理する方法が一番簡単です。ページを見るだけで、探している情報はページの中央上部のセクションにあることが分かります。HTMLの知識が限られていても、探しているデータがすべて同じ <table> 要素の下に格納されていること、そしてこのテーブルには、その日のデータ内容に関係なく、常に "Appar Temp" や "Dewpoint" のような単語が入っていることは、簡単に推測できます。

分かったことを書き留めて、ページが生成したXHTMLを考えます。"Appar Temp" をテキスト検索すると、図4 に示すように、このテキストは実際に必要なデータがすべて格納されているテーブルの中に入っていることが分かります。このテーブルを参照点、あるいはアンカーとします。

図4: アンカーを見つけるには、"Appar Temp" というテキストが入っているテーブルを探す
図4: アンカーを見つけるには、

このアンカーを探す方法が必要です。XSLを使ってXMLを変換するつもりなので、このタスクにはXPath式を使用できます。平凡な選択肢として、次の式を使うことにします。

/html/body/center/table[6]/tr[2]/td[2]/table[2]/tr/td/table[6]

この式では、ルートの<html> 要素からアンカーまでのパスを指定します。この平凡なアプローチの場合は、このページのレイアウト変更の影響を非常に受けやすくなります。もっと良いアプローチとして、アンカーの周りのコンテンツに基づいてアンカーを指定する方法があります。このアプローチを使って、XPath式を次のように作り直します。

//table[starts-with(tr/td/font/b,'Appar Temp')]

あるいは、XSLを使ってXMLツリーをストリングに変換することもできます。

//table[starts-with(normalize-space(.), 'Appar Temp')]

データをXMLにマップする

このアンカーが見つかったら、実際にデータを抽出するコードを作成することができます。このコードは、XSLファイルの形式です。XSLファイルの目的は、アンカーを識別し、そのアンカーから (ショート・ホップで) 探しているデータに移動する方法を指定し、希望する書式でXML出力ファイルを生成することです。このプロセスは、実際には思うほど難しくありません。これを実行するXSLのコードをリスト2 に示します。また、XSLテキスト・ファイルとしても入手できます。

<xsl:output> 要素は、変換の結果としてXMLを希望することを単にプロセッサーに伝えるものです。1つ目の <xsl:template> で、ルート要素が確立され、<xsl:apply-templates> が呼び出されてアンカーが検索されます。2つ目の<xsl:template> で、不要なマッチングを除外します。最後の <xsl:template> で、アンカーをmatch 属性で定義し、プロセッサーに、抽出する温度データと湿度データにホップする方法を伝えます。

もちろん、XSLを作成しただけでは、変換は実行されません。変換を実行するツールも必要です。このためには、XSLを構文解析して変換を実行する XMLHelper クラスのメソッドを利用します。これらのタスクを実行するメソッドは、それぞれparseXMLFromURL()transformXML() です。これらのメソッドを使用するためのコードをリスト3に示します。

リスト3
/**
 * Retrieve the XHTML file written to disk in the Listing 1
 * and apply our XSL Transformation to it. Write the result
 * to disk as XML.
 */
public static void main(String args[]) {
  try {
    Document xhtml = XMLHelper.parseXMLFromURLString("file://weather.xml");
    Document xsl   = XMLHelper.parseXMLFromURLString("file://XSL/weather.xsl");
    Document xml   = XMLHelper.transformXML(xhtml, xsl);
    XMLHelper.outputXMLToFile("XML" + File.separator + "result.xml");
  } catch (XMLHelperException xmle) {
    // ... Do Something ...
  }
}

結果をマージして処理する

データ抽出を一度しか実行しない場合は、これで終わりです。しかし、ある時刻の温度だけを知りたいのではありません。さまざまな時間の温度を知りたい場合は、抽出プロセスを繰り返し、その結果を1つのXMLデータ・ファイルにマージする必要があります。この場合、再びXSLを使用することもできますが、XMLファイルのマージには、 XMLHelper クラスの残る1つのメソッドを作成します。mergeXML() メソッドは、現在の抽出で取得したデータを、過去の抽出データのアーカイブ・ファイルにマージすることができます。

このプロセス全体を実行するコードについては、WeatherExtractor.java ファイルを参照してください。プログラムの実行をスケジュールする方法はシステムによって異なり、簡単なプログラムだけでは対処できない場合が多いので、ここでは省略します。4日間、1日1回 WeatherExtractor を実行した結果については、図5 を参照してください。

図5. Web抽出の結果
図5. Web抽出の結果

最後に

本稿では、世界最大の情報源であるWebから情報を抽出する強力なアプローチの基礎を例を交えて説明しました。また、抽出プログラムの経験の少ないJava開発者でも手間をかけずに抽出作業を始められるように、コーディング・ツールも紹介しました。本稿の例は、ワシントン州シアトルの天気情報を抽出することだけに焦点を当てたものですが、ここで紹介したコードはほとんどすべて、どのようなデータ抽出にも利用できます。実際、WeatherExtractor クラスの小さい変更を除けば、他のデータ・マイニング・プロジェクトで変更が必要となるコードは、XSL変換コードだけです (ちなみに、コンパイルする必要がないものです)。

この方法は、信頼できると同時に簡単でもあります。信頼性の高いデータ・ソースを選び、そのソース内で書式ではなく内容に結び付いたアンカーを選べば、メンテナンスの必要が少ない、信頼性の高いデータ抽出システムを作成できます。また、経験のレベルと抽出するデータの量によっても変わりますが、作成から実行まで1時間もかからないでしょう。

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=295727
ArticleTitle=Webベースのデータ・マイニング
publish-date=06012001