【SeleniumBasic】要素が存在するかどうか【VBA】

スクレイピングで、訪問先のページに要素(Element)が存在するかどうか分からないときの対応方法について記事にします。

IsElementPresentを使えばよいのですが、なぜか私の環境では引数のByオブジェクトでうまくいかず、しばらくはまってしまったので。

大前提として、私は参照設定を最小限しか設定しないという環境にあります(盛大なネタバレ)。

要素が存在しない場合とは

ハローワークで求人検索をすると、通常、次のように対象件数が表示されます。

次のメッセージは、要素が存在しないときがあります。

この要素のタグは図にある通りです。

開発者コンソールでこの部分のタグ上で右クリックし「コピー」を選び、さらに「XPathをコピー」を選ぶと(図参照)、

XPathを採取

//*[@id=”ID_form_1″]/div[6]/div[1]/div/span

というXPathを採取できます。

ところが、検索条件によっては、次の図のようなメッセージを表示し、件数が表示されないときがあります。

動的に生成される要素の例

この「ご希望の条件に合致する情報は見つかりませんでした。」というメッセージが表示されたときに、先ほどの//*[@id=”ID_form_1″]/div[6]/div[1]/div/spanというXPathを指定してFindElementByXpathを使っても、エラーになります。

IsElementPresent

そこで、このような動的に生成されるタグ(要素)があるかどうか調べるために、IsElementPresentを使います。IsElementPresentは、引数で指定した要素が存在すればTrueを、なければFalseを返します。

IsElementPresentをVBEのF2(オブジェクトブラウザ)で検索すると、WebDriverクラスのメソッドであることが分かります(Selenium Type Libraryを参照設定してある場合)。

引数にBy型の値をもちます。

こういったサイト↓を参考にしました。

https://vba-labo.rs-techdev.com/archives/1888

IsElementPresentの使い方については、私のサイトでは紹介しません。Webの海にある優良なサイト様をご参照ください(他力本願)。

By型ではまる

さてここで私はBy型の引数でエラーになり、しばらく抜け出せなくなりました。

私が試したコードは下記です。

    '件数把握
    Dim myBy As By

    If driver.IsElementPresent(myBy.ID("msg_area")) Then
        '「ご希望の条件に合致する情報は見つかりませんでした。」
        'MsgBox ""
    Else
       '件数があったときの処理
       '(省略)
    End If

私は配布のときは参照設定を外しますが、デバッグ段階では参照設定をしていることが多いです。今回も、これを実行するときにはSelenium Type Libraryを参照設定していました。

ところが、このコードを実行したところエラーになりました。

エラーメッセージ
エラーの個所

なんで?・・・しばらく訳が分かりませんでした。サイトに紹介されていたコードをそのまま使ったつもりだったのですが・・・・。

理由は、オブジェクト変数であるmyByを初期化していないことでした。

こちらのサイト↓を参考にしたのですが、

https://vba-labo.rs-techdev.com/archives/1888

こちらでは、宣言と同時に初期化する方式をとっていたのでした。

Dim myBy As New By

ところが、宣言と同時に初期化する方式にしておくと、配布の段階で、参照設定もユーザに委ねないといけなくなります。

参照設定というのは、Javaのimport、Cのincludeのようなものなんですが、プログラムなんて知らない人には「は????何それ????」という状態になり、説明がめんどうなので、私は極力参照設定が必要ないようなコードを作って配布するようにしています。

そこで私は宣言と同時に初期化する方式は採用していません。

その代わり、宣言とは別に初期化するステップを入れる必要がありました。それを忘れていたのでした(かなり初歩的なミスでして・・・・お恥ずかしい)。

という訳で、エラーにならないコードは次のとおりです。

    '件数把握
    Dim myBy As By
    Set myBy = New By

    If driver.IsElementPresent(myBy.ID("msg_area")) Then
        '「ご希望の条件に合致する情報は見つかりませんでした。」
        'MsgBox ""
    Else
       '件数があったときの処理
       '(省略)
    End If
    

さらに、参照設定を完全に外す段階で、次のように記述を見直しました。

    '件数把握
    Dim myBy As Object
    Set myBy = CreateObject("Selenium.By")


    If driver.IsElementPresent(myBy.ID("msg_area")) Then
        '「ご希望の条件に合致する情報は見つかりませんでした。」
        'MsgBox ""
    Else
       '件数があったときの処理
       '(省略)
    End If

By型は、冗長に記述するなら、Selenium.By型です。

これをCreateObjectで記述するなら、CreateObject(“Selenium.By”)となります。

CreateObjectはいろいろ使っていますが、Selenium.Byというものも生成できたのですね。今回初めて使いました。

以上、私がBy型ではまったコードのあるマクロブックをZipにして置いておきます。

https://kn-sharoushi.com/wp-content/uploads/2023/03/20230324getJobSeekerInfo.zip

以前、この記事で紹介したものと同じです。求人サイトから特定の条件で検索して、賃金相場を調べるための一覧を作ります。

参照設定はしなくてもよいのですが、SeleniumBasicをインストールしておかないといけませんし、.Net Frameworkも必要です。Chrome用のWebDriverも必要でのでご注意を。