Excel VBAでieのフレームページを操作する
2018/11/12
一般サイトではほぼ見なくなったフレームページですが、企業が活用するシステムでは現役で活躍しているフレームページもまだまだあるようです。
ですので、今回はieに表示されたフレームページをVBAで操作することについてまとめてみます。
フレームページとは
フレームページとは、通常の画面は1つのhtmlで構成されますが、ページを上下や左右に分割して複数のページから構成されるページのことを言います。
と書いてもなかなかわかりにくいので、HTMLベースで記載すると以下の通りです
親ページ
1 2 3 4 5 6 7 8 9 10 11 12 |
<html> <head> <title>親ページ</title> <meta http-equiv="content-type" charset="utf-8"> </head> <frameset cols="50%,*" rows="*"> <frame src="01.html" name="menu"> <frame src="02.html" name="naiyou"> </frameset> <body> </body> </html> |
子ページ1(01.html)
1 2 3 4 5 6 7 8 9 10 11 |
<html> <head> <title>子ページ1</title> <meta http-equiv="content-type" charset="utf-8"> </head> <body> 子ページ(その1) </body> </html> |
子ページ2(02.html)
1 2 3 4 5 6 7 8 9 10 11 |
<html> <head> <title>子ページ2</title> <meta http-equiv="content-type" charset="utf-8"> </head> <body> 子ページ(その2) </body> </html> |
上記例示では、左右に子ページを並べて表示
左側のページには「01.html」を表示し、右側のページには「02.html」を表示すると定義しています。
このように複数のページから1つのページを構成可能としているのがフレームページとなります。
子ページの数を調べる
子ページの数を調べるには、以下の通り
1 |
ieDoc.frames.Length |
フレームの情報はDocumentの「frames」内に収録されてます。
「Length」は直訳すると「長さ」になりますが、ここでは「数」が収録されます。
このフレーム数を実際にメッセージボックスに子ページの数を表示させようとすると、以下のロジックをコピペしてサイトのURLを修正すれば表示されます。
なお、フレームページが複数のフレームページから構成(フレームページの中にさらにフレームページがあるようなケース)されていても、親から呼ばれる子ページの数しか表示されません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
'変数を必ず宣言 Option Explicit '変数を宣言 Dim objIE As InternetExplorer Dim ieDoc As HTMLDocument Sub IE_open() 'Internet Exploreを立ち上げる Set objIE = CreateObject("InternetExplorer.Application") objIE.Visible = True 'URLを指定する objIE.Navigate2 "https://ie-excel.com/example/frame/" '該当のWebサイトが表示されるのを待つ While objIE.Busy Or objIE.readyState <> READYSTATE_COMPLETE DoEvents Wend 'ドキュメントをieDocにセット Set ieDoc = objIE.document 'フレームの数を表示 MsgBox ieDoc.frames.Length 'オブジェクト参照を解除 Set ieDoc = Nothing Set objIE = Nothing End Sub |
子ページの要素を操作する
子ページは、Documentのframesにメンバーとして収録されています。
そのため子ページの要素を操作するには、それぞれのフレームページを特定する必要があります。
フレーム番号は「0」から始まりますので、子ページが2つあればフレーム番号は「0」と「1」になります。
1 |
ieDoc.frames(フレーム番号).document.Title |
以下はフレーム番号「0」のタイトルタグを表示する場合の記述です
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
'変数を必ず宣言 Option Explicit '変数を宣言 Dim objIE As InternetExplorer Dim ieDoc As HTMLDocument Sub IE_open() 'Internet Exploreを立ち上げる Set objIE = CreateObject("InternetExplorer.Application") objIE.Visible = True 'URLを指定する objIE.Navigate2 "https://ie-excel.com/example/frames" '該当のWebサイトが表示されるのを待つ While objIE.Busy Or objIE.readyState <> READYSTATE_COMPLETE DoEvents Wend 'ドキュメントをieDocにセット Set ieDoc = objIE.document '2番目のフレームのタイトルを表示 MsgBox ieDoc.frames(1).document.Title 'オブジェクト参照を解除 Set ieDoc = Nothing Set objIE = Nothing End Sub |
フレームページ以外は「ieDoc」からタグを操作していましたが、フレームページの子ページを操作するのは「ieDoc.frames(フレーム番号).Document」を操作することとなります。
タグ名やClass、IDでタグを特定したい場合、「getElementsByTagName」などを使用すれば操作が可能となります。
Busyが一時的に解除される
通常であれば画面が遷移したことを待つのに、以下の通りシェル自体の「Busy」および「readyState」の状態それぞれを確認にします。
フレームページではないサイトの画面遷移待ち
1 2 3 |
While objIE.Busy Or objIE.readyState <> READYSTATE_COMPLETE DoEvents Wend |
- 「Busy」はシェルにしかない
- シェルの「readyState」に加え、ドキュメントにもredayStateがり各ページ毎に返却
- 親ページを読み込んだ時点で「Busy」が一時的に「False」になるが、子ページ読み込み始めると「True」になる
したがって、上記のロジックでは親ページの読み込みしか判定できないこと。そして、Busyが一時的に「False」となった時点を捉えてしまうと、子ページの読み込みが終了していないにも関わらず、画面遷移が終了したと判断されてしまいます。
実際にBusyとReadyStateの関係は調べると、あるサイトでは以下の通りとなりました。
時刻 | Busy | シェルのReadyState | 親ページのReadyState | 子ページ(1)のReadyState | 子ページ(2)のReadyState |
---|---|---|---|---|---|
11:26:53 344 | TRUE | 3 | interactive | loading | loading |
11:26:53 423 | TRUE | 3 | interactive | interactive | loading |
11:26:53 438 | FALSE | 4 | complete | complete | loading |
11:26:53 484 | TRUE | 4 | complete | complete | loading |
11:26:53 500 | TRUE | 4 | complete | complete | loading |
11:26:53 516 | TRUE | 4 | complete | complete | interactive |
11:26:53 766 | FALSE | 4 | complete | complete | complete |
11:26:53 781 | FALSE | 4 | complete | complete | complete |
フレームページの場合の画面遷移待ち方法
フレームページでは、親ページの「Busy」そして親ページと全子ページの「ReadyState」の状態をすべて確認しなければならないため、あまりきれいではないものの以下のようなロジックであれば、親ページのみならず、子ページの画面がきちんと表示されていることも確認できます。
Busyは途中で解除されることがあるため、まずは子ページのReadyStateをすべて確認。子ページの表示が終了を確認
その上で、親ページの「Busy」と「ReadyState」を確認する方法がフレームページにおける画面遷移の待機方法となります。
フレームページの画面遷移待ち
1 2 3 4 5 6 7 8 9 10 11 12 |
For i = 0 To ieDoc.frames.Length - 1 On Error Resume Next Set frameDoc = ieDoc.frames(i).document On Error GoTo 0 If Not frameDoc Is Nothing Then While frameDoc.readyState <> "complete" DoEvents Wend End If Next |
フレームページの各要素を操作する
フレームページの各要素を操作、つまりボタンをクリックしたり、テキストを入力したり、ラジオボタンを選択するには、インストールされたExcelの状態では操作できません。
そのため、「Microsoft HTML Object Library」を使用することが必要となります。
「Microsoft HTML Object Library」を使用するためには、以下を実施ください
- ExcelでVBA(コードの表示)を開く
- デザインウィンドウの「ツール」→「参照設定」メニューから、[Microsoft HTML Object Library]にチェックをつける
これを実施することで、「FramesCollection」が利用可能となります。
フレームのBodyタグ内のHTMLソースを取得するソース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
'変数を必ず宣言 Option Explicit '変数を宣言 Dim objIE As InternetExplorer Dim ieDoc As HTMLDocument Dim frameDoc As HTMLDocument Dim i As Integer Sub IE_open() 'Internet Exploreを立ち上げる Set objIE = CreateObject("InternetExplorer.Application") objIE.Visible = True '指定のURLを開く objIE.Navigate2 "https://ie-excel.com/example/frame/" '該当のWebサイトが表示されるのを待つ While objIE.Busy Or objIE.readyState <> READYSTATE_COMPLETE DoEvents Wend 'ドキュメントをieDocにセット Set ieDoc = objIE.document 'フレームの数だけ処理を実行 For i = 0 To ieDoc.frames.Length - 1 On Error Resume Next Set frameDoc = ieDoc.frames(i).document On Error GoTo 0 If Not frameDoc Is Nothing Then While frameDoc.readyState <> "complete" DoEvents Wend End If Set frameDoc = Nothing Next Set frameDoc = ieDoc.frames(1).document MsgBox frameDoc.Title Set frameDoc = Nothing Set ieDoc = Nothing Set objIE = Nothing End Sub |