VBAでIEの親要素と子要素を取得
<< エクセルVBAでIEのhead要素とbody要素を取得する :前の記事
前回はhtml要素の子要素であるhead要素とbody要素を取得する方法について解説しました。また「オブジェクトまでの道筋」を詳しく説明しましたので、少しは理解できるようになったかと思います。今回は、IE(InternetExplorer)の指定した要素に対して親要素と子要素を取得する方法について解説します。
ここでは、親要素・子要素の関係性とプロパティによる取得範囲の違いについて解説しています。こちらを理解すると一般的な方法でデータ取得ができない場合に変則技で取得するなど応用することができます。
目次
- DOM(Document Object Model)とは
- HTML(HyperText Markup Language)とは
- タグと要素(エレメント)の違い
- 指定した要素の親要素と子要素を取得する処理の流れ
- 利用するサブルーチン・プロパティ・VBA関数について
- body要素の子要素を取得するサンプルコード
- 指定した要素の親要素を取得するサンプルコード
- parentElementプロパティとChildrenプロパティの使い方
- まとめ
DOM(Document Object Model)とは
DOMとは「Document Object Model」の略称で、html・head・body・p・aなどのHTMLドキュメント要素にアクセスして取得や操作ができる仕組みのことです。
以下はHTMLドキュメントをツリー構造に表したものでDOMツリーと呼ばれます。階層状のツリー構造でHTMLドキュメントを表現します。
HTML(HyperText Markup Language)とは
HTMLとは「HyperText Markup Language」の略称で、Webページを作成するために開発された言語です。世の中に公開されているWebページのほとんどがHTMLで作成されています。こちらのサイトもHTMLで作成されています。
HTMLは基本的に以下のような構成でできており「<タグ名>★テキスト★</タグ名>」が1つの要素(エレメント)になります。この中の特定の要素に対してデータの取得や操作を行っていきます。
<html>
<head>
<title>VBAのIE制御</title>
</head>
<body>
<p>こちらはpタグのテキストです。</p>
<a href="★リンクURL★">リンクのアンカーテキストです。</a>
</body>
</html>
タグと要素(エレメント)の違い
HTML言語では、「タグ」と呼ばれる仕組みを利用して構築していきます。以下のイメージを確認すると分かりやすいと思いますが、タグとは「<」と「>」で構成されており、開始タグと終了タグまでの括りで1つの要素を形成します。
具体例で説明するとWebページのタイトルを表す「titleタグ」を利用して開始タグの「<title>」と終了タグの「</title>」で括り、タグの中の文字列が「要素内容」となります。こちらでは「VBAのIE制御入門」の文字列が要素内容となります。
そして、こちらの「開始タグ+要素内容+終了タグ」の全体を「要素」と呼びます。また、別名では「エレメント」と呼ばれますので、どちらも同じ意味であることを理解してください。
指定した要素の親要素と子要素を取得する処理の流れ
以下が今回の処理の流れになります。
- ①変数宣言
- ②ieViewサブルーチンを利用して指定したURLをIEで起動
- ③HTMLドキュメントのオブジェクトを取得
- ④HTMLドキュメント内のbody要素を取得
- ⑤body要素に対しての子要素を取得
- ⑥メッセージボックスにbody要素の子要素を表示
- ⑦body要素に対しての親要素を取得
- ⑧メッセージボックスにbody要素の親要素を表示
利用するサブルーチン・プロパティ・VBA関数について
今回利用するサブルーチン・プロパティ・VBA関数は以下になります。
- ieViewサブルーチン
- ieCheckサブルーチン
- Documentプロパティとは
- headプロパティとは
- bodyプロパティとは
- Allプロパティとは
- parentElementプロパティとは
- Childrenプロパティとは
- outerHTMLプロパティとは
- Lengthプロパティとは
- MsgBox関数とは
ieViewサブルーチンとは
ieViewサブルーチンは指定したURLをInternetExplorerで起動させ、Webページが完全に読み込まれるまで待機処理をするマクロです。
ieCheckサブルーチンとは
ieCheckサブルーチンは指定したInternetExplorerオブジェクトのWebページが完全に読み込まれるまで待機処理をするマクロです。
Documentプロパティとは
InternetExplorerオブジェクトのDocumentプロパティはHTMLドキュメントのオブジェクトを返すプロパティです。これによりHTMLドキュメントを操作することができます。
headプロパティとは
DocumentオブジェクトのheadプロパティはHTMLドキュメント内のhead要素オブジェクトを返すプロパティです。
bodyプロパティとは
DocumentオブジェクトのbodyプロパティはHTMLドキュメント内のbody要素オブジェクトを返すプロパティです。
Allプロパティとは
DocumentオブジェクトのAllプロパティはHTMLドキュメント内の全ての要素オブジェクトを返すプロパティです。
objIE.document.All(添え字).プロパティ/メソッド
parentElementプロパティとは
IEオブジェクトのparentElementプロパティは指定した要素(エレメント)の親要素オブジェクトを返すプロパティです。
childrenプロパティとは
IEオブジェクトのchildrenプロパティは指定した要素(エレメント)の直下にある子要素オブジェクトを返すプロパティです。
outerHTMLプロパティとは
要素オブジェクトのouterHTMLプロパティは指定した要素オブジェクトの要素タグとそのタグに含まれるHTMLを取得するプロパティです。
Lengthプロパティとは
AllコレクションのLengthプロパティは指定したAllコレクションの全ての要素数を取得するプロパティです。
MsgBox関数とは
MsgBox関数はダイアログボックスにメッセージとボタンを表示し、どのボタンが押されたかを示す整数型の数値を返します。
body要素の子要素を取得するサンプルコード
こちらのVBAコードは、IE(InternetExplorer)のbody要素の子要素を取得するサンプルコードマクロです。
Sub sample()
Dim objIE As InternetExplorer
Dim objCld As HTMLDocument, objAll As HTMLDocument
'データ抽出用ページをIE(InternetExplorer)で起動
Call ieView(objIE, "http://www.vba-ie.net/code/all.html")
'①body要素の直下にある子要素の1番目の要素を取得する
MsgBox objIE.document.body.Children(0).outerHTML
'②body要素の全ての要素の1番目の要素を取得する
MsgBox objIE.document.body.all(0).outerHTML
'①の要素数を取得
MsgBox "Childrenコレクションの要素数 : " & _
objIE.document.body.Children.length
'②の要素数を取得
MsgBox "allコレクションの要素数 : " & _
objIE.document.body.all.length
'①の直下にある子要素を表示する
For Each objCld In objIE.document.body.Children
MsgBox "Childrenコレクションの要素 : " & _
objCld.outerHTML
Next
'②の全ての子要素を表示する
For Each objAll In objIE.document.body.all
MsgBox "allコレクションの要素 : " & _
objAll.outerHTML
Next
End Sub
実行結果
※2015年1月現在の結果です。Webページ更新により内容が変わっている場合もあります。
解説
Sub sample()
Dim objIE As InternetExplorer
Dim objCld As HTMLDocument, objAll As HTMLDocument
こちらはSubステートメントに引数の設定がないsampleプロシージャになります。 まずは、変数宣言でメモリ領域を割り当てるDimステートメントを利用してオブジェクト変数objIEに「InternetExplorer型」を、オブジェクト変数objCldとオブジェクト変数objAllに「HTMLDocument型」を変数宣言しています。
'データ抽出用ページをIE(InternetExplorer)で起動
Call ieView(objIE, "http://www.vba-ie.net/code/all.html")
次に他のプロシージャを呼び出すCallステートメントを利用してieViewサブルーチンを呼び出しています。第一引数にはオブジェクト変数の「objIE」を第二引数には表示させるURLの「http://www.vba-ie.net/code/all.html」を設定しています。これによりInternetExplorerでデータ抽出用ページが表示されます。
'①body要素の直下にある子要素の1番目の要素を取得する
MsgBox objIE.document.body.Children(0).outerHTML
'②body要素の全ての要素の1番目の要素を取得する
MsgBox objIE.document.body.all(0).outerHTML
ここからはbody要素のChildrenプロパティとallプロパティの違いについて解説していきます。以下は理解しやすい様にVBAコードとキーワードの関連性を列挙したものです。あくまで関連性ですので必ずしも「=(イコール)」ではありません。
- 【objIE.document.body.Children(0).outerHTML】
- 【objIE.document.body.all(0).outerHTML】
- 【objIE.document.body.Children.length】
- 【objIE.document.body.all.length】
- objIE = InternetExplorerオブジェクト
- document = HTMLドキュメントのオブジェクト(Documentオブジェクト)
- body = Documentオブジェクトのbody要素オブジェクト
- Children = body要素オブジェクトの直下にある子要素(Childrenプロパティ)
- All = body要素オブジェクトの全ての子要素(allプロパティ)
- Children(0) = Childrenコレクションの1番目の子要素オブジェクト
- All(0) = Allコレクションの1番目の要素オブジェクト
- outerHTML = 指定オブジェクトの要素タグとそのタグに含まれるHTMLコード
- length = 指定オブジェクトの要素数
まず、InternetExplorerオブジェクトのdocumentプロパティを利用してHTMLドキュメントのオブジェクト(Documentオブジェクト)を取得します。
次にDocumentオブジェクトのbodyプロパティを利用してHTMLドキュメントのbody要素を取得します。そして、body要素オブジェクトのChildrenプロパティを利用して、body要素の直下にある子要素を、Allプロパティを利用して、body要素のすべての要素取得します。
ここまででbody要素のそれぞれの要素をコレクションとして取得しました。ここからは、ChildrenコレクションとAllコレクションの中から1番目の要素を取得します。1番目の要素とは「Children(0)」「All(0)」の部分で、括弧内の数字(添え字)は「0」から数えるため、1番目の要素の添え字は「0」となります。
そして、1番目の要素オブジェクトのouterHTMLプロパティを利用して、1番目の要素の要素タグとそのタグに含まれるHTMLコードを取得します。尚、共に1番目の要素オブジェクトは「<h1>~</h1>」になります。
それぞれ、処理はbody要素の下位要素を取得するもので結果も同じでしたが、それぞれ取得する要素の内容が異なりますので注意が必要です。まずは、簡単に確認する方法として要素数を取得するLengthプロパティを利用してそれぞれの要素数を確認してみましょう。
'①の要素数を取得
MsgBox "Childrenコレクションの要素数 : " & _
objIE.document.body.Children.length
'②の要素数を取得
MsgBox "allコレクションの要素数 : " & _
objIE.document.body.all.length
こちらはそれぞれの要素数を取得する処理になります。結果を見ると要素数が異なっているのが分かるかと思います。続いて、更に詳しく確認するために要素のデータをすべて抽出して確認してみます。
'①の直下にある子要素を表示する
For Each objCld In objIE.document.body.Children
MsgBox "Childrenコレクションの要素 : " & _
objCld.outerHTML
Next
'②の全ての子要素を表示する
For Each objAll In objIE.document.body.all
MsgBox "allコレクションの要素 : " & _
objAll.outerHTML
Next
End Sub
こちらでは、For Each~Nextステートメントを利用してbody要素から取得したそれぞれの要素の数だけループ処理を行っています。設定するコレクションは、body要素オブジェクトのChildrenプロパティとAllプロパティで取得したコレクションになります。
ループ処理内の処理は、指定した要素オブジェクトのouterHTMLプロパティを利用して、指定した要素オブジェクトの要素タグとそのタグに含まれるHTMLコードを取得します。
取得したデータはMsgBox関数の引数に設定して、メッセージボックスに表示させていますので、どのような形で要素が格納されているのかを確認してみてください。
最初はほとんど違いについて分かりにくいかと思いますが、「ul要素」の次の要素を確認すると違いが分かります。以下の画像はその部分だけを抜粋したものです。
Childrenプロパティは、「ul要素」の次に「h2要素」を表示しているのに対してAllプロパティは「li要素」を表示しています。このようにChildrenプロパティはあくまで指定したオブジェクトつまりbody要素オブジェクトの子要素だけを取得しており、その更に下位の「li要素」である孫要素は対象外ということになります。
それに対してAllプロパティは、子要素・孫要素関係なく指定したオブジェクトの下位にあるすべての要素を取得しますので、この違いがあることを理解しましょう。
最後は、Endステートメントを利用してプロシージャを終了させます。子要素の取得について理解できたところで、続いては親要素の取得について解説します。
指定した要素の親要素を取得するサンプルコード
こちらのVBAコードは、IE(InternetExplorer)の指定した要素の親要素を取得するマクロです。
Sub sample()
Dim objIE As InternetExplorer
Dim objCld As HTMLDocument, objAll As HTMLDocument
'データ抽出用ページをIE(InternetExplorer)で起動
Call ieView(objIE, "http://www.vba-ie.net/code/all.html")
'処理①body要素の親要素を取得する
MsgBox objIE.document.body.parentElement.outerHTML
'処理②head要素の親要素を取得する
MsgBox objIE.document.head.parentElement.outerHTML
'処理③body要素の親要素を取得する
MsgBox objIE.document.all.tags("li")(0).parentElement.outerHTML
'処理④body要素の親要素を取得する
MsgBox objIE.document.all.tags("li")(1).parentElement.outerHTML
End Sub
実行結果
メッセージボックスに個々の取得した要素が表示されます。
解説
Sub sample()
Dim objIE As InternetExplorer
Dim objCld As HTMLDocument, objAll As HTMLDocument
まずは、Dimステートメントを利用してオブジェクト変数objIEに「InternetExplorer型」をオブジェクト変数objCld,objAllに「HTMLDocument型」を、宣言します。
'データ抽出用ページをIE(InternetExplorer)で起動
Call ieView(objIE, "http://www.vba-ie.net/code/all.html")
次にCallステートメントを利用してieViewサブルーチンを呼び出し、IE(InternetExplorer)でデータ抽出用ページを表示します。
'処理①body要素の親要素を取得する
MsgBox objIE.document.body.parentElement.outerHTML
'処理②head要素の親要素を取得する
MsgBox objIE.document.head.parentElement.outerHTML
ここからは指定した要素の親要素の取得について解説していきます。こちらも理解しやすい様にVBAコードとキーワードの関連性を列挙します。
- 【objIE.document.body.parentElement.outerHTML】
- 【objIE.document.head.parentElement.outerHTML】
- 【objIE.document.all.tags("li")(0).parentElement.outerHTML】
- objIE = InternetExplorerオブジェクト
- document = HTMLドキュメントのオブジェクト(Documentオブジェクト)
- body = Documentオブジェクトのbody要素オブジェクト
- head = Documentオブジェクトのhead要素オブジェクト
- parentElement = 指定した要素オブジェクトの親要素(parentElementプロパティ)
- All = Documentオブジェクトの全ての子要素(allプロパティ)
- tags("li") = allコレクション内のli要素コレクション(tagsメソッド)
- tags("li")(0) = li要素コレクションの1番目の要素オブジェクト
- outerHTML = 指定オブジェクトの要素タグとそのタグに含まれるHTMLコード
まず、documentプロパティを利用してHTMLドキュメントのオブジェクト(Documentオブジェクト)を取得します。
次にbodyプロパティを利用してHTMLドキュメントのbody要素を取得します。そして、body要素オブジェクトのparentElementプロパティを利用して、body要素の親要素を取得します。
これでbody要素の親要素である「<html>~</html>」が取得できました。次に親要素のouterHTMLプロパティを利用して、親要素の要素タグとそのタグに含まれるHTMLコードを取得し、MsgBox関数でメッセージボックスに表示させます。
続いてhead要素の処理を見てみると結果はbody要素と同じで親要素は「<html>~</html>」になります。当然の結果と思っている方はしっかりHTMLドキュメントのツリー構造を理解している証拠です。分からなかった方は以下を確認すると理解できるかと思いますが、head要素とbody要素の親要素はhtml要素になります。よって、どちらもparentElementプロパティを利用するとhtml要素を取得します。
'処理③body要素の親要素を取得する
MsgBox objIE.document.all.tags("li")(0).parentElement.outerHTML
'処理④body要素の親要素を取得する
MsgBox objIE.document.all.tags("li")(1).parentElement.outerHTML
こちらはli要素の親要素を取得しています。tagsメソッドには「li」がセットされていますので、全てのli要素を取得をしています。「tags("li")(0)」「tags("li")(1)」はli要素の1番目と2番目のli要素になりますが、parentElementプロパティを利用して親要素を取得すると、共に「<ul>~</ul>」を取得しています。こちらも以下の図を確認すると分かりますが、全てのli要素の親要素は「ul要素」になっています。ですので、どのli要素も同じ親要素を取得します。
parentElementプロパティとChildrenプロパティの使い方
ここまでparentElementプロパティとChildrenプロパティがどのようなものかを解説していきます。そもそもこのプロパティはどのような場面で利用するのかと疑問を持つ方もいるかと思いますが、何の特徴もないサイトなどで以外と威力を発揮します。
IE(InternetExplorer)でWebページの特定した情報を取得する場合は、基本的に「一意のキーワード」を探し出して取得します。「一意のキーワード」とは、HTMLドキュメント内で特定のキーワードが1つしかないものを指します。例えば、id属性です。id属性は1ページに1回しか利用できないというルールがあります。(実際に記述自体はできますが・・・)以下の事例で言えばid属性「test」が一意のキーワードになります。
<p>普通のpタグです。</p>
<p id="test">id属性にテストが設定されています。</p>
<p>普通のpタグです。</p>
<p>普通のpタグです。</p>
データの取得はその要素オブジェクトをどのような道筋で取得するかがポイントと何度も説明しているように特定できる場所があれば簡単にデータを取得できます。例えば以下の場合、「★★★のp要素」と「2番目のul要素」を取得したい場合どのようにしたらよいでしょうか。こちらは一部分だけを抽出していますが、前後には同じような記述が複数あり特定ができない状態とします。
<div>
<p>pタグです。</p>
<p>pタグです。</p>
<p>★★★</p>
<div id="test">
<p>pタグです。</p>
<ul>
<li>ulタグ1です。</li>
<li>ulタグ1です。</li>
<li>ulタグ1です。</li>
<li>ulタグ1です。</li>
</ul>
<ul>
<li>ulタグ2です。</li>
<li>ulタグ2です。</li>
<li>ulタグ2です。</li>
<li>ulタグ2です。</li>
</ul>
</div>
</div>
このように取得したい要素が他の要素と区別する部分がない場合は、直接その要素を取得する以外の方法から対応しなければいけません。この時に便利なのがparentElementプロパティとChildrenプロパティになります。以下は取得方法の1例になりますので確認してください。
Sub sample()
Dim objIE As InternetExplorer
Dim objCld As HTMLDocument, objAll As HTMLDocument
'データ抽出用ページをIE(InternetExplorer)で起動
Call ieView(objIE, "http://www.vba-ie.net/code/all.html")
'①「★★★」のp要素を取得する
MsgBox objIE.document.all("test").parentElement.all.tags("p")(2).outerHTML
'②2番目のul要素を取得する
MsgBox objIE.document.all("test").Children(2).outerHTML
End Sub
まず、「★★★のp要素」の取得ですが、こちらのpタグにはid属性もなく特定するものが1つもありません。このような場合は、近くに特定できるキーワードを探します。今回一番近くにある一意のキーワードといえば、id属性の「test」になります。
こちらを基点にどうにか目標の要素にたどり着く方法を考えていきます。まず目に付くのがp要素とid属性「test」の親要素である「div要素」です。もちろんこのdiv要素もキーワードがありませんので、そのまま取得することは困難です。ただし、このdiv要素から3番目の子要素を取得する道筋をたどると「★★★のp要素」を取得することができます。
'①「★★★」のp要素を取得する
MsgBox objIE.document.all("test").parentElement.all.tags("p")(2).outerHTML
こちらが実際にその方法で取得したVBAコードですが、まずAllプロパティからid属性「test」のdiv要素を取得します。次にparentElementプロパティを利用してp要素とdiv要素の共通の親要素である「div要素」を取得します。そこからさらにAllプロパティでdiv要素内の全ての要素を取得して、p要素の3番目の要素つまり「★★★のp要素」を取得します。
このようにある特定の要素から一旦親要素まで上がりそこから目的の子要素へとたどり着く方法は、とても有効な方法です。もちろん簡単に特定できるものがあればそちらを基点にすれば問題ないですが、どうしても見つからない場合は、目的の要素の周りを見て判断するとよいかと思います。
'②2番目のul要素を取得する
MsgBox objIE.document.all("test").Children(2).outerHTML
続いてこちらは「2番目のul要素」を取得するVBAコードです。こちらは、Childrenプロパティを利用してid属性「test」の3番目の子要素つまり「2番目のul要素」を取得しています。ここでポイントとなるのはAllプロパティとの違いです。
Childrenプロパティは直下の子要素だけを、Allプロパティは指定した要素内のすべての要素を取得すると解説しました。もちろんこちらはAllプロパティを利用しても取得できます。
ただし、Allプロパティを利用場合は、すべての要素を順番に数える必要があります。今回は数が少ないので簡単に数えることは可能ですが、要素数が多かったり階層が複雑になると数えるだけでも大変です。そのような場合はChildrenプロパティを利用して大きく目的の位置まで取得してから、そこからAllプロパティを利用するなどした方が効率がよいです。
まとめ
今回は、IE(InternetExplorer)の指定した要素に対して親要素と子要素を取得する方法について解説します。指定した要素からどの道筋をたどっていけば目的の要素を取得できるかが分かったかと思います。次回は、指定した要素オブジェクトのHTMLコードを取得する方法について解説します。
次の記事: エクセルVBAで指定した要素オブジェクトのHTMLコードを取得する >>
近田 伸矢, 植木 悠二, 上田 寛
IEのデータ収集&自動操作のプログラミング本はこの1冊だけ!IEの起動やポップアップウィンドウ、表示を制御する基本的なコードはもちろん、テキストボックスやラジオボタン、表、ハイパーリンクなどのHTML部品を制御する方法など、自動操作に欠かせないノウハウを丁寧に解説。