SeleniumBasicでHタグを順番にリストアップする方法

WebElementから指定したH1、H2、H3のタグは以下のコードで出来ます。

FindElementsByTag("H1")
FindElementsByTag("H2")
FindElementsByTag("H3")

しかし、H1~H3のタグを出てきた順に取得することはできません。
FindElementByTagでORが使う事ができれば解決するのですが・・・

解決策1:OR条件が使える Xpathを使う

以下のXpathを指定すると FindElementsByXpath でコレクションが取得できるので、For Eachで出てきた順にタグを取得することができます。

//*[  self::h1 and not(.=preceding::h1) 
    or self::h2 and not(.=preceding::h2)
    or self::h3 and not(.=preceding::h3)  ]

実際のコーディング例

' Xpathでマッチングさせる方法
Function GetHeadingList(objWeb As Object, iLevel As String) As String
    Dim i As Integer ' ループ用のカウンタ変数
    Dim sXpath As String ' Xpath条件を格納する文字列
    Dim sRtn As String ' 最終的な結果を格納する文字列
    Dim elmLoop As WebElement ' ループ内で使用する要素を格納する変数
    
    ' 指定されたレベル(見出しの階層)までループ
    For i = 1 To iLevel
        If i <> 1 Then sXpath = sXpath & "or "

        ' Xpathで要素を選択する条件を構築
        sXpath = sXpath & " self::h" & i & " and not(.=preceding::h" & i & ")"
    Next
        
    ' Xpath条件に一致する要素を検索
    For Each elmLoop In objWeb.FindElementsByXPath("//*[" & sXpath & "]")
        ' 見出しのタグ名とテキストを取得し、改行を整形して結果に追加
        sRtn = sRtn & elmLoop.tagname & vbTab & Replace(Replace(elmLoop.Text, vbCr, ""), vbLf, "") & vbCrLf
    Next

    ' 結果文字列の末尾の改行を削除して関数の結果として返す
    GetHeadingList = Left(sRtn, Len(sRtn) - Len(vbCrLf))
End Function

解決策2:FindElementsByTagを使う

FindElementsByTagではなんと * が使えます。
* を指定すると全タグを順に取得できます。
ただし遅いです。 
速度を気にせず、とにかく目的を達成できれば良いという時には有用な手段の1つになるかと思います。

以下コーディング例

' 全タグを調べる方法(遅い)
Function GetHeadingList2(objWeb As Object) As String
    Dim elmLoop As WebElement ' ループ内で使用する要素を格納する変数
    Dim sRtn As String ' 最終的な結果を格納する文字列
    
    ' ウェブページ上の全要素をタグごとにループ
    For Each elmLoop In objWeb.FindElementsByTag("*")
        Select Case UCase(elmLoop.tagname) ' 要素のタグ名を大文字に変換し比較
            Case "H1", "H2", "H3", "H4", "H5", "H6" ' 見出し要素(h1, h2, h3, h4, h5, h6)を検出
                ' 見出しのタグ名とテキストを取得し、改行を整形して結果に追加
                sRtn = sRtn & elmLoop.tagname & vbTab & Replace(Replace(elmLoop.Text, vbCr, ""), vbLf, "") & vbCrLf
        End Select
    Next
    ' 結果文字列の末尾の改行を削除して関数の結果として返す
    GetHeadingList2 = Left(sRtn, Len(sRtn) - Len(vbCrLf))
End Function

使用方法

Sub Main()
    ' PhantomJSDriverオブジェクトを作成
    Dim driver As New PhantomJSDriver
    ' 一時的な文字列変数を宣言
    Dim sTmp As String
    
    ' ループを使って200回改行を出力(デバッグ用途)
    Dim i As Integer: For i = 1 To 200: Debug.Print: Next
    
    ' PhantomJSDriverオブジェクトの操作を始める
    With driver
        ' ウェブページを指定のURL(https://florentbr.github.io/SeleniumBasic/)にアクセス
        .Get "https://florentbr.github.io/SeleniumBasic/"
        ' GetHeadingList関数を使用して、指定のレベル(4)の見出しリストを取得し、sTmp変数に格納
        sTmp = GetHeadingList(driver, 4)
        ' 取得した見出しリストをデバッグ出力
        Debug.Print sTmp
        ' 区切り線(50文字のハイフン)をデバッグ出力
        Debug.Print String(50, "-")
        ' GetHeadingList2関数を使用して、見出しリストを取得し、sTmp変数に格納
        sTmp = GetHeadingList2(driver)
        ' 取得した見出しリストをデバッグ出力
        Debug.Print sTmp
    End With
End Sub

実行結果

h1  Seleniumbasic
h2  A Selenium based browser automation framework for VB.Net, VBA and VBScript
h3  Description
h3  Download
h3  Bug tracker
h3  Third party software
h3  Tested environments
h3  Authors and Contributors
--------------------------------------------------
h1  Seleniumbasic
h2  A Selenium based browser automation framework for VB.Net, VBA and VBScript
h3  Description
h3  Download
h3  Bug tracker
h3  Third party software
h3  Tested environments
h3  Authors and Contributors

全ソース

Option Explicit

Sub Main()
    ' PhantomJSDriverを使用するためのドライバーオブジェクトを作成
    Dim driver As New PhantomJSDriver
    ' 一時的な文字列を格納する変数
    Dim sTmp As String

    ' 200回のループを実行し、空行を表示する
    Dim i As Integer
    For i = 1 To 200
        Debug.Print
    Next

    ' PhantomJSDriverオブジェクトを使用して指定のウェブページにアクセスし、見出しリストを取得
    With driver
        .Get "https://florentbr.github.io/SeleniumBasic/" ' 指定URLにアクセス
        sTmp = GetHeadingList(driver, 4) ' レベル4の見出しリストを取得
        Debug.Print sTmp ' 見出しリストを表示
        Debug.Print String(50, "-") ' 区切り線を表示
        sTmp = GetHeadingList2(driver) ' 全ての見出しを取得
        Debug.Print sTmp ' 見出しリストを表示
    End With
End Sub

' Xpathでマッチングさせる方法で見出しリストを取得
Function GetHeadingList(objWeb As Object, iLevel As String) As String
    Dim i As Integer
    Dim sXpath As String
    Dim sRtn As String
    Dim elmLoop As WebElement

    ' 指定したレベルの見出しに対応するXPathを構築
    For i = 1 To iLevel
        If i <> 1 Then
            sXpath = sXpath & "or "
        End If
        sXpath = sXpath & "self::h" & i & " and not(.=preceding::h" & i & ")"
    Next

    ' 構築したXPathにマッチする要素を探し、テキストを取得して見出しリストを作成
    For Each elmLoop In objWeb.FindElementsByXPath("//*[" & sXpath & "]")
        sRtn = sRtn & elmLoop.tagname & vbTab & Replace(Replace(elmLoop.Text, vbCr, ""), vbLf, "") & vbCrLf
    Next

    GetHeadingList = Left(sRtn, Len(sRtn) - Len(vbCrLf))
End Function

' すべてのタグを調べる方法で見出しリストを取得
Function GetHeadingList2(objWeb As Object) As String
    Dim elmLoop As WebElement
    Dim sRtn As String

    ' すべてのタグをループして、H1からH6までの見出しのテキストを取得
    For Each elmLoop In objWeb.FindElementsByTag("*")
        Select Case UCase(elmLoop.tagname)
            Case "H1", "H2", "H3", "H4", "H5", "H6"
                sRtn = sRtn & elmLoop.tagname & vbTab & Replace(Replace(elmLoop.Text, vbCr, ""), vbLf, "") & vbCrLf
        End Select
    Next
    GetHeadingList2 = Left(sRtn, Len(sRtn) - Len(vbCrLf))
End Function

コメント

  1. スポーツ用品店no より:

    FindElementsByTagではなんと * が使えます。
    * を指定すると全タグを順に取得できます。
    ただし遅いです。 

    のところ、とても驚きました。
    なんと*が使えるんですね。
    大変助かりました。

タイトルとURLをコピーしました