フォーチュンサモナーズ
«前の日記(2003-10-12) 最新 次の日記(2003-10-14)» 編集

Don'tStopMusic

2003|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|02|03|04|05|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|08|09|10|

カテゴリ別 2003年 | 2004年 | 2005年 | 2006年 | 2007年 | 2008年

知り合いサイト: よんだもの / 暴想 / Linuxでやる夫 / 新宿Vipper / 僕だけが幸せになればいいのに。


2003-10-13

_ [Ruby] HTML パーサ : htmlsplit その 1 このエントリーを含むブックマーク

猫も杓子も XML なご時世ですが、ウェブ上のリソースのほとんどはまだ HTML です。HTML を解析・加工するニーズはまだまだなくなることはないでしょう。ということで Ruby で利用できる HTML パーサについて調べていきます。まずは moonwolf さんの htmlsplit から。対象は htmlsplit バージョン 1.02 です。
htmlsplit は HTML に特化したタグ付き文書パーサと言って良いと思います。パースされたテキストはタグやタグに挟まれた文字列に分解されますので、例えばリンクだけ抽出するなどの処理ができます。まずはちょっとした例をあげて、htmlsplit がどのように HTML ファイルを処理するのか見ていきます。
サンプルプログラム: htmlsplit_example.rb / 実行結果 htmlsplit_example.out
では細かく見ていきましょう。htmlsplit で HTML をパースする一般的な手順は以下のようになります。 HTMLSplit.new(string) は受け取った文字列をパースして、結果を格納した HTMLSplit オブジェクトを返します。さらに、HTMLSplit#document でパース済みオブジェクトの配列(Array)を得ることができます。あとはイテレータを使って各要素に対して順に処理をしけばよいという寸法です。さて、HTML のソースと出力結果とを比較していきます。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
→
#<Declaration:0x40202b48 @text="DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"">
見ての通り文書型宣言は Declaration オブジェクトになります。
<html lang="ja-JP">
→
#<StartTag:0x40202634 @attr={"lang"=>"ja-JP"}, @name="html">
開始タグは StartTag オブジェクトになります。タグ名は StartTag#name で取得できます。また、属性は StartTag#attr[](name) で得られまので、上の例では以下のようになります。
<title>htmlsplit test html</title>
→
#<StartTag:0x40202120 @attr=nil, @name="title">
#<CharacterData:0x40201f54 @text="htmlsplit test html">
#<EndTag:0x40201c48 @name="title">
タグとそれに挟まれた文字列の例です。テキスト部分は CharacterData オブジェクト、閉じタグは EndTag オブジェクトになります。属性のない StartTag オブジェクトの attr インスタンス変数は nil となることに注意してください。確実に属性があることが分かっていない場合には StartTag#attr が存在することを確かめてから値を参照する必要があります。つまり、すべての要素の id 属性の値を表示したいなどという場合には次のように書かなければなりません。
<a href='http://www.example.org' target=_blank foo_attr>example</a>
→
#<StartTag:0x401ffa60 @attr={"href"=>"http://www.example.org", "foo_attr"=>true, "target"=>"_blank"}, @name="a">
#<CharacterData:0x401ff984 @text="example">
#<EndTag:0x401ff81c @name="a">
属性はダブルクォーテーションで囲まれていても、シングルクォーテーションで囲まれていても、あるいは囲まれていなくてもきちんと属性としてパースされます。また、属性名=値 の形ではなく 属性名 だけの属性の値は true になります。
<hr></hr>
→
#<EmptyElementTag:0x401ff664 @attr=nil, @name="hr">
#<EndTag:0x401ff45c @name="hr">
子要素を持たない空要素タグの例です。<hr> <br> などの空要素タグは EmptyElementTag オブジェクトになります。ですが htmlsplit は前後の文脈を判断するということは特に行いませんので、</hr> はそのまま EndTag オブジェクトとなります。
<hoge>not html tag</hoge>
→
#<StartTag:0x40200294 @attr=nil, @name="hoge">
#<CharacterData:0x40200154 @text="not html tag">
#<EndTag:0x401ffec0 @name="hoge">
htmlsplit は文書の妥当性は検証しませんので、HTML で定義されていないタグも区別なくパースできます。
<div><span>Lorem ipsum.</div></span>
→
#<StartTag:0x401febec @attr=nil, @name="div">
#<StartTag:0x401fe994 @attr=nil, @name="span">
#<CharacterData:0x401fe854 @text="Lorem ipsum.">
#<EndTag:0x401fe624 @name="div">
#<EndTag:0x401fe354 @name="span">
さらにタグの入れ子関係が正しいかどうかも検証しません。
<hr/><hr />
→
#<StartTag:0x401fe124 @attr=nil, @name="hr/">
#<EmptyElementTag:0x401fdeb8 @attr={"/"=>true}, @name="hr">
XHTML の空要素タグの書き方には対応していません。/ は要素名の一部か属性として扱われます。

_ [Ruby] HTML パーサ : htmlsplit その 2 このエントリーを含むブックマーク

例題: リンクの抽出 htmlsplit_example_02.rb 実行時のコマンドライン引数で指定した HTML ファイルからリンクを抽出します。a タグか img タグしか調べません。他のタグからも抽出したいという場合は条件分岐をざくざくと増やすことになります。document は Array ですので each メソッドではなく、collect メソッドなどを使ってもいいと思います。 参考までに上のプログラムをSAX パーサ風に書き直すとこうなります
[]

最近のコメント:

  1. 岩崎正則 (11-24)
  2. だて (11-15)
  3. usata (11-09)

RSS
Creative Commons License
This work is licensed under a Creative Commons License
(note: text only. w/o web design, citations, (re)distributed softwares).