IE制御ライブラリ
はじめに
RubyからIEを制御するのに便利なライブラリを作ってみた。 基本的な考え方は、
- IE制御用のWIN32OLEオブジェクトをラップするクラスを用意
- IE.Document で返すDocumentオブジェクト、IE.Document.BodyやIE.Document.Framesで返すオブジェクトも できるだけラップして、それらが返すタグエレメント*1もラップしてしまえば IEのタグエレメント自体が持っているメソッドだけでなく、自分で用意したメソッドも使えるようになる
IE制御ライブラリ
まだ作ったばかりなので、ちょこちょこ変わると思います。DL後、"ie_lib.rb"にリネームしてください。
テストケース
RubyUnitを使ったテストケースです。
IE制御ライブラリで提供しているクラスとメソッド
IE_Wrapper
これから説明する各クラスのスーパークラス。 未定義のメソッドがあったら、IEのオリジナルオブジェクトに転送する機構とかを持っている。
これから説明するクラスはIEオリジナルのオブジェクトをラップしている。 ラップオブジェクトに使えば、中身の生のIEオリジナルのオブジェクトを返す。 例えば、IE::TagElementがAタグエレメントを保持していたら、rawメソッドで生のAタグエレメントを取得できる。
IE Class
IEのOLEオブジェクトをラップするクラス。
IEを起動する。引数を省略すれば可視な状態でIEが起動します。戻り値はIEのOLEオブジェクト。
urlで示されるページを表示する。IEオリジナルのnavigateと違って、ページが表示されるまで戻ってこない。
処理が完了するまでIEを待たせたいときに使う。
IEが現在表示中のドキュメントを示すIE::Documentオブジェクトを返す。
IE::Document
IEのDocumentオブジェクトをラップするクラス。
表示中のドキュメントのBodyエレメントを示すIE::TagElementを返す。
表示中のドキュメントのHeadエレメントを示すIE::TagElementを返す。
IEが表示中のページが複数のフレームから構成されている場合、フレームのリストを示すIE::Framesオブジェクトを返す。 引数でindexを指定すると、index番目のフレームを示すIE::Frameオブジェクトを返す(最初のフレームはindex=0)。
IE::Frames
IEのFrameのコレクションをラップするクラス。
index番目のフレームを示すIE::Frameオブジェクトを返す。index=0が最初のフレーム。
Frameコレクションに含まれているフレームの数を返す*2。
Frameコレクションのイテレータ。
IE.document.frames.each {|frame|
p frame
}
IE::Frame
IEのFrameオブジェクトをラップするクラス。各フレームの中にDocumentオブジェクトがある。
本フレームの中に含まれるDocumentオブジェクトを返す。
IE::TagElementCollection
IEのタグエレメントのコレクションをラップしている。この中に複数のタグエレメントが含まれている。
index番目のタグエレメントをラップしているIE::TagElementオブジェクトを返す。
コレクションに含まれるタグエレメントの数を返す。
TagElementコレクションのイテレータ。
IE.document.body.tags("A").each {|tag_element|
p tag_element
}
- get_tag_by_title(target_str)
- get_tag_by_value(target_str)
- get_tag_by_text(target_str)
- get_tag_by_name(target_str)
- get_tag_by_option(target_str)
タグコレクションの中から目的のタグエレメントを探す。みつかったらTagElementオブジェクトを返す。 複数のTagElementがマッチした場合は配列で返される*3。
- get_tag_by_title()はボタンの表題を指定してINPUTタグのボタンを見つける時に使う。
- get_tag_by_value()はINPUTタグのvalue属性を指定してINPUTタグを見つける時に使う。
- get_tag_by_text()はそのタグが囲んでいるテキスト内の文字列をキーにタグエレメントを探す時に使う。
- get_tag_by_option()は<SELECT>タグを探すのに使う。検索キーには<SELECT>タグの選択肢を使う。
この2つは正規表現で検索するので、一部でもマッチしているTagElementを返す。
- get_tag_by_name()はタグにつけられたname属性をキーにタグエレメントを検索する。こちらは完全一致で検索する。
IE::TagElement
IEのタグエレメントをラップするクラス。
タグの名前を返すメソッド。<IMG>タグエレメントなら"IMG"を返す。
INPUTタグのように文字列の入力可能なタグに文字列をセットする。
クリック可能なタグエレメントをクリックする。オリジナルのclickと違って、IEの状態が安定するまで戻ってこない。
現在のタグエレメントに含まれるタグエレメントからtag_nameで示されるタグエレメントのコレクションを返す。 戻りはTagElementCollectionオブジェクト。
まず、TABLEタグエレメントを特定し、その中に含まれるTDタグエレメントのコレクションを得るのに使う。
タグエレメントが囲んでいる文字列を返す。これで情報を得る。
使い方
Googleで検索するサンプル
役には立たないが、Googleでキーワードを検索するサンプルを示す。目的のタグを見つけるにはコツがあるので、作っていく過程とともに説明してみる。
まず、キーワードを入れるタグとボタンのタグを探すために、全部のINPUTタグエレメントを表示させてみる。
# ie_sample_01.rb
require 'ie_lib'
ie = IE.new
ie.navigate("http://www.google.com/")
input_list = ie.document.body.tags("INPUT")
input_list.each {|element|
p element
}
> ruby -Ks ie_sample_01.rb
IE::TagElement:<INPUT>:[<INPUT maxLength=256 size=55 name=q>]
IE::TagElement:<INPUT>:[<INPUT type=hidden value=UTF-8 name=ie>]
IE::TagElement:<INPUT>:[<INPUT type=hidden value=UTF-8 name=oe>]
IE::TagElement:<INPUT>:[<INPUT type=hidden value=ja name=hl>]
IE::TagElement:<INPUT>:[<INPUT type=submit value="Google 検索" name=btnG>]
IE::TagElement:<INPUT>:[<INPUT type=submit value="I'm Feeling Lucky" name=btnI>]
IE::TagElement:<INPUT>:[<INPUT id=all type=radio CHECKED value="" name=lr>]
IE::TagElement:<INPUT>:[<INPUT id=il type=radio value=lang_ja name=lr>]
この結果から入力欄に'q'という名前がついているのがわかる。よって、input_list.get_tag_by_name("q")で入力タグが手に入る。 取得したタグエレメントに.text="xxx"で文字列を設定する。
検索ボタンは"Google 検索"というラベルが付いているので、input_list.get_tag_by_title("検索")で手に入る*4。取得したタグエレメントにclickメソッドを作用させれば検索結果が表示される。
require 'ie_lib'
ie = IE.new
ie.navigate("http://www.google.com/")
input_list = ie.document.body.tags("INPUT")
input_list.get_tag_by_name('q').text = "ruby win32ole"
input_list.get_tag_by_title("検索").click
Yahooの乗り換え案内を使ってみる
会社から帰る時に、Yahooの乗り換え案内を起動して、電車の接続を見るサンプル。 これも、同じく、まずはタグエレメントの一覧をpで表示して、目的のタグを探す。
# ie_sample_02.rb
require 'ie_lib'
ie = IE.new
ie.navigate("http://transit.yahoo.co.jp/")
input_list = ie.document.body.tags("INPUT")
input_list.each {|input_element|
p input_element
}
> ruby -Ks ie_sample_02.rb
IE::TagElement:<INPUT>:[<INPUT type=hidden value=select name=val_htmb>]
IE::TagElement:<INPUT>:[<INPUT onkeypress=yj_set_focus_blur() id=yj_set_focus_here size=14 name=val_from>]
IE::TagElement:<INPUT>:[<INPUT size=14 name=val_to>]
IE::TagElement:<INPUT>:[<INPUT type=checkbox value=CHARGE name=val_dsmask_charge>]
IE::TagElement:<INPUT>:[<INPUT type=checkbox value=AIR name=val_dsmask_air>]
IE::TagElement:<INPUT>:[<INPUT type=radio value=DEP name=val_timekb>]
IE::TagElement:<INPUT>:[<INPUT type=radio value=ARR name=val_timekb>]
IE::TagElement:<INPUT>:[<INPUT type=radio value=LST name=val_timekb>]
IE::TagElement:<INPUT>:[<INPUT type=radio CHECKED value=NON name=val_timekb>]
IE::TagElement:<INPUT>:[<INPUT type=submit value=" 探 索 ">]
出発駅は"name=val_from"、到着駅は"name=val_to"。「出発時間指定」にチェックを入れたい。このチェックは"value=DEP"だろうと あたりをつける。探索ボタンはget_tag_by_title("探索")で探せばよい。
探索ボタンをクリックすると、ページが表示されるが、駅名が重複する場合は候補が表示される(一発で表示される場合もある)。 その場合、<SELECT>タグで候補が表示される。<SELECT>タグの候補には上記サンプルの場合、"三鷹"と"三鷹台"が表示される。
- まず、この<SELECT>タグを特定するために、ie.document.body.tags("SELECT").get_tag_by_option("三鷹") で<SELECT>タグ エレメントを特定
- SELECTタグエレメントのオプションを指定するのは、select_element.text = "三鷹" でできるようにしている*5
require 'ie_lib'
ie = IE.new
ie.navigate("http://transit.yahoo.co.jp/")
input_list = ie.document.body.tags("INPUT")
input_list.get_tag_by_name("val_from").text = "三鷹"
input_list.get_tag_by_name("val_to").text = "羽村"
input_list.get_tag_by_title("DEP").click # 「出発時間指定」にチェックを入れる
input_list.get_tag_by_title("探索").click # 「探索」ボタンをクリック
# 候補が表示される場合は、
select_list = ie.document.body.tags("SELECT")
select_list.get_tag_by_option("三鷹").text = "三鷹" # もともと選択されているから不要なんだが
input_list = ie.document.body.tags("INPUT")
input_list.get_tag_by_title("探索").click # 「探索」ボタンをクリック
ライセンス
ライセンスはRubyのライセンスに従います。
Copyright (C) 2003 Oka Yasushi <yac@tech-notes.dyndns.org>
You may redistribute it and/or modify it under the same license terms as Ruby.
免責事項
本プログラムは無保証です。作者は、プログラム自身のバグ、あるいは、本プログラムの実行など から発生するいかなる損害に対しても責任を持ちません。
変更履歴
- IE::Body Class廃止。Document.BodyをIE::TagElementに置き換え
- IE::Document#head で<HEAD>IE::TagElementを返すようにした
Initial Release
戻る
*1タグ要素を示すオブジェクト
*2IEにはlengthというプロパティがあるが、Ruby的にはsizeの方がすっきりするので。
*3このメソッドであまり大量のTagElementがマッチしないように注意する。
TagElementCollectionはIE内部の1個オブジェクトをラップしているだけだが、このメソッドで返される配列にたくさんのTagElementが
含まれると、TagElementの数だけIEのオブジェクトをラップすることになる。IEとCOMがどこまで耐えられるか不安だ。
*4タグについている
ラベルは改行コードやスペースなどが削除された後、正規表現で探されるので、"Google 検索"では探せない。やるなら"Google検索"で
探す。
*5SELECTタグの
処理は本当は結構めんどくさい。IEライブラリでその辺を隠蔽している。