VBAの勉強を始めてみた

色々試しています。

VBAでIEを操る(ページ移動後にDOMや要素を再取得しなかったらどうなるのか?)

今回は、変数に取得したDOMや要素が、ページ移動後、どんな挙動になるか調べてみます。
ページを移動した後、DOMツリー構造が変わるので、再取得する必要があるだろう・・・・・・と予想できます。が、実際はどうなのか、書籍やネットから腑に落ちる情報を見つけられなかったので、実験してみます。

目次

 

実験に使うのは、以下のHTML文書です。

 

ページ移動前

f:id:kouten0430:20180906164812j:plain

↑このページのソース

<html>
<body>
<p id="ichibanjukusita">りんご</p>
<p>りんご</p>
<p>りんご</p>
<p>りんご</p>
<p>りんご</p>
</body>
</html> 

 

ページ移動後

f:id:kouten0430:20180906164905j:plain

↑このページのソース

<html>
<body>
<p id="ichibanjukusita">みかん</p>
<p>みかん</p>
<p>みかん</p>
<p>みかん</p>
<p>みかん</p>
</body>
</html>

 

この二つのHTML文書を使い、ページ移動前と移動後で、DOMと要素がどうなるのかローカルウィンドウで観察します。

結論から言うと

  • メソッドで取得する要素は、ページ移動後に再取得する必要がある
  • プロパティで取得するDOMは、ページ移動後に再取得する必要なし

 

この結論を得るために、過剰ですが、8パターンの実験をしてみました。

 

要素ひとつを変数に取得し、ページ移動後、再取得せずに使用した場合

Sub test()
    Dim ie As Object
    Dim sh As Object
    Dim win As Object
    Dim myElem As Object
    Dim ページ移動前 As String
    Dim ページ移動後 As String
    
    Set sh = CreateObject("Shell.Application")
    
    For Each win In sh.Windows
        If win.Name = "Internet Explorer" Then
            Set ie = win
            Exit For
        End If
    Next
    
    Set myElem = ie.document.getElementsByTagName("p")(0)
    
    ページ移動前 = myElem.innerText
    
    ie.navigate "C:\Users\みかん.html"
    
    ページ移動後 = myElem.innerText
    
End Sub

 

りんごの木になっている「りんご」を取りに登った、変数の myElem君。

f:id:kouten0430:20180906165300j:plain

 

「りんご」を取ったあとに「みかん」も欲しくなったので、みかんの木に移動したけれど、みかんの木の登りかた(メソッド)が分からなかったので

f:id:kouten0430:20180906165449j:plain

 

「みかん」を手に入れることはできなかった・・・・・・。

 

要素ひとつを変数に取得し、ページ移動後、再取得した場合

Sub test()
    Dim ie As Object
    Dim sh As Object
    Dim win As Object
    Dim myElem As Object
    Dim ページ移動前 As String
    Dim ページ移動後 As String
    
    Set sh = CreateObject("Shell.Application")
    
    For Each win In sh.Windows
        If win.Name = "Internet Explorer" Then
            Set ie = win
            Exit For
        End If
    Next
    
    Set myElem = ie.document.getElementsByTagName("p")(0)
    
    ページ移動前 = myElem.innerText
    
    ie.navigate "C:\Users\みかん.html"
    
    Set myElem = ie.document.getElementsByTagName("p")(0)
    
    ページ移動後 = myElem.innerText
    
End Sub

 

またまた、りんごの木になっている「りんご」を取りに登った myElem君。

「りんご」を取ったあとに「みかん」も欲しくなったので、みかんの木に移動し、みかんの木の登りかた(メソッド)を知っていたので

f:id:kouten0430:20180906165637j:plain

 

「みかん」も手に入れることができた。

 

同じ要素すべてを変数に取得し、ページ移動後、再取得せずに使用した場合

Sub test()
    Dim ie As Object
    Dim sh As Object
    Dim win As Object
    Dim myCollection As Object
    Dim ページ移動前 As String
    Dim ページ移動後 As String
    
    Set sh = CreateObject("Shell.Application")
    
    For Each win In sh.Windows
        If win.Name = "Internet Explorer" Then
            Set ie = win
            Exit For
        End If
    Next
    
    Set myCollection = ie.document.getElementsByTagName("p")
    
    ページ移動前 = myCollection(0).innerText
    
    ie.navigate "C:\Users\みかん.html"
    
    ページ移動後 = myCollection(0).innerText
    
End Sub

 

myCollection君は大きなハンマーでりんごの木を叩き、「りんご」をすべて落としてから、「りんご」をひとつ入手した。

f:id:kouten0430:20180906165958j:plain

 

しばらくして「みかん」も欲しくなったので、みかんの木に移動したけれど、myCollection君はハンマーを持ってこなかったので、

f:id:kouten0430:20180906170012j:plain

 

「みかん」を手に入れることはできなかった・・・・・・。

 

同じ要素すべてを変数に取得し、ページ移動後、再取得した場合

Sub test()
    Dim ie As Object
    Dim sh As Object
    Dim win As Object
    Dim myCollection As Object
    Dim ページ移動前 As String
    Dim ページ移動後 As String
    
    Set sh = CreateObject("Shell.Application")
    
    For Each win In sh.Windows
        If win.Name = "Internet Explorer" Then
            Set ie = win
            Exit For
        End If
    Next
    
    Set myCollection = ie.document.getElementsByTagName("p")
    
    ページ移動前 = myCollection(0).innerText
    
    ie.navigate "C:\Users\みかん.html"
    
    Set myCollection = ie.document.getElementsByTagName("p")
    
    ページ移動後 = myCollection(0).innerText
    
End Sub

 

myCollection君は「りんご」を取ったあと、みかんの木がある場所にハンマーを持ってきたので、「みかん」をすべて落とし、目的の「みかん」を入手することに成功した。

f:id:kouten0430:20180906170217j:plain

 

IDで指定した要素を変数に取得し、ページ移動後、再取得せずに使用した場合

Sub test()
    Dim ie As Object
    Dim sh As Object
    Dim win As Object
    Dim myId As Object
    Dim ページ移動前 As String
    Dim ページ移動後 As String
    
    Set sh = CreateObject("Shell.Application")
    
    For Each win In sh.Windows
        If win.Name = "Internet Explorer" Then
            Set ie = win
            Exit For
        End If
    Next
    
    Set myId = ie.document.getElementById("ichibanjukusita")
    
    ページ移動前 = myId.innerText
    
    ie.navigate "C:\Users\みかん.html"
    
    ページ移動後 = myId.innerText
    
End Sub

 

myId君は、目印のついている実を打ち落とすことができる魔法の銃を持っています。まず、「りんご」を打ち落とし、

f:id:kouten0430:20180906170407j:plain

 

次にみかんの木に移動しました。・・・・・・が、目印を忘れてしまったため、

f:id:kouten0430:20180906170424j:plain

 

「みかん」を打ち落とすことができませんでした・・・・・・。

 

IDで指定した要素を変数に取得し、ページ移動後、再取得した場合

Sub test()
    Dim ie As Object
    Dim sh As Object
    Dim win As Object
    Dim myId As Object
    Dim ページ移動前 As String
    Dim ページ移動後 As String
    
    Set sh = CreateObject("Shell.Application")
    
    For Each win In sh.Windows
        If win.Name = "Internet Explorer" Then
            Set ie = win
            Exit For
        End If
    Next
    
    Set myId = ie.document.getElementById("ichibanjukusita")
    
    ページ移動前 = myId.innerText
    
    ie.navigate "C:\Users\みかん.html"
    
    Set myId = ie.document.getElementById("ichibanjukusita")
    
    ページ移動後 = myId.innerText
    
End Sub

 

myId君は「りんご」を取ったあと、みかんの木に移動しました。今度は、目印の"ichibanjukusita"を思い出したので、

f:id:kouten0430:20180906170558j:plain

 

「みかん」も打ち落とすことができました。

 

documentプロパティでDOMを変数に取得し、ページ移動後、再取得せずに使用した場合

Sub test()
    Dim ie As Object
    Dim sh As Object
    Dim win As Object
    Dim myDoc As Object
    Dim ページ移動前 As String
    Dim ページ移動後 As String
    
    Set sh = CreateObject("Shell.Application")
    
    For Each win In sh.Windows
        If win.Name = "Internet Explorer" Then
            Set ie = win
            Exit For
        End If
    Next
    
    Set myDoc = ie.document
    
    ページ移動前 = myDoc.getElementsByTagName("p")(0).innerText
    
    ie.navigate "C:\Users\みかん.html"
    
    ページ移動後 = myDoc.getElementsByTagName("p")(0).innerText
    
End Sub

 

myDocさんは、みんなに木の実の取り方を教えてくれる先生です。
myDocさんは、一つのから望遠鏡を使って、いろんな場所にある木のかたちを見ることができます。しかし、一回望遠鏡を使ってしまえば、あとは望遠鏡なしでも、いろんな場所にある木のかたちをライブで見ることができます。

f:id:kouten0430:20180906170740j:plain

 

これは、望遠鏡の使用で発動する myDocさんの特殊能力です。

 

documentプロパティでDOMを変数に取得し、ページ移動後、再取得した場合

Sub test()
    Dim ie As Object
    Dim sh As Object
    Dim win As Object
    Dim myDoc As Object
    Dim ページ移動前 As String
    Dim ページ移動後 As String
    
    Set sh = CreateObject("Shell.Application")
    
    For Each win In sh.Windows
        If win.Name = "Internet Explorer" Then
            Set ie = win
            Exit For
        End If
    Next
    
    Set myDoc = ie.document
    
    ページ移動前 = myDoc.getElementsByTagName("p")(0).innerText
    
    ie.navigate "C:\Users\みかん.html"
    
    Set myDoc = ie.document
    
    ページ移動後 = myDoc.getElementsByTagName("p")(0).innerText
    
End Sub

 

myDocさんは一回望遠鏡を使ってしまえば、あとは望遠鏡なしでもいろんな場所にある木のかたちをライブで見ることができます。だからその都度、望遠鏡を使っていろんな場所にある木を見ることができるのは当然ですね。

f:id:kouten0430:20180906170941j:plain

 

まとめ

8パターンの実験結果は、下記のようになりました。

方法 りんご入手 みかん入手
要素1個を変数に取得し、ページ移動後、変数をそのまま利用 OK NG
要素1個を変数に取得し、ページ移動後、変数に再取得して利用 OK OK
要素のすべてを変数に取得し、ページ移動後、変数をそのまま利用 OK NG
要素のすべてを変数に取得し、ページ移動後、変数に再取得して利用 OK OK
IDから要素1個を変数に取得し、ページ移動後、変数をそのまま利用 OK NG
IDから要素1個を変数に取得し、ページ移動後、変数に再取得して利用 OK OK
documentプロパティでDOMを変数に取得し、ページ移動後、変数をそのまま利用 OK OK
documentプロパティでDOMを変数に取得し、ページ移動後、変数に再取得して利用 OK OK

 
冒頭で結論を先に言ってしまったので繰り返しになりますが、

ページを移動したら

  • 要素は再取得する必要がある
  • DOM は(変数に入っていても)再取得しなくてよい。常に最新の状態である

 

ということが、実験で分かりました。