ie-excel

エクセル・マクロでie操作

Excel VBAでieのフレームページを操作する

2018/11/12

一般サイトではほぼ見なくなったフレームページですが、企業が活用するシステムでは現役で活躍しているフレームページもまだまだあるようです。

ですので、今回はieに表示されたフレームページをVBAで操作することについてまとめてみます。

フレームページとは

フレームページとは、通常の画面は1つのhtmlで構成されますが、ページを上下や左右に分割して複数のページから構成されるページのことを言います。

と書いてもなかなかわかりにくいので、HTMLベースで記載すると以下の通りです

親ページ
<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)
<html>
  <head>
    <title>子ページ1</title>
    <meta http-equiv="content-type" charset="utf-8">
  </head>
  <body>

  子ページ(その1)

  </body>
</html>
子ページ2(02.html)
<html>
  <head>
    <title>子ページ2</title>
    <meta http-equiv="content-type" charset="utf-8">
  </head>
  <body>

  子ページ(その2)

  </body>
</html>

子ページは普通のhtmlとなります。

上記例示では、左右に子ページを並べて表示
左側のページには「01.html」を表示し、右側のページには「02.html」を表示すると定義しています。

このように複数のページから1つのページを構成可能としているのがフレームページとなります。

フレームページのサンプルページ

 

子ページの数を調べる

子ページの数を調べるには、以下の通り

ieDoc.frames.Length

フレームの情報はDocumentの「frames」内に収録されてます。
「Length」は直訳すると「長さ」になりますが、ここでは「数」が収録されます。

このフレーム数を実際にメッセージボックスに子ページの数を表示させようとすると、以下のロジックをコピペしてサイトのURLを修正すれば表示されます。

なお、フレームページが複数のフレームページから構成(フレームページの中にさらにフレームページがあるようなケース)されていても、親から呼ばれる子ページの数しか表示されません。

'変数を必ず宣言
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」になります。

ieDoc.frames(フレーム番号).document.Title

以下はフレーム番号「0」のタイトルタグを表示する場合の記述です

'変数を必ず宣言
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」の状態それぞれを確認にします。

フレームページではないサイトの画面遷移待ち
  While objIE.Busy Or objIE.readyState <> READYSTATE_COMPLETE
    DoEvents
  Wend

ところが、フレームページの「Busy」と「ReadyState」は以下の通りとなります。

  • 「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」を確認する方法がフレームページにおける画面遷移の待機方法となります。

フレームページの画面遷移待ち
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」を使用するためには、以下を実施ください

  1. ExcelでVBA(コードの表示)を開く
  2. デザインウィンドウの「ツール」→「参照設定」メニューから、[Microsoft HTML Object Library]にチェックをつける

これを実施することで、「FramesCollection」が利用可能となります。

フレームのBodyタグ内のHTMLソースを取得するソース
'変数を必ず宣言
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

 

-ExcelでIE操作