【InternetExplorer】地図の距離と時間を取得する【Seleniumなしで】【WebDriverなしで】
- [記事公開]2023.04.24
- VBA
- ExcelVBA, InternetExplorer
この記事の続きです。
この記事ではSeleniumBasicとChromeとVBAを使って、Googleマップのルート検索から、出発地と目的地を入力し、かかる所要時間と所要距離を把握する処理を紹介しました。
詳しいコードは記事を見ていただくとして、私が本当にやりたかったことは、この先にあります。
それは何かというと、ある一定の職場環境では、SeleniumBasicもCromeのWebDriverもダウンロードできないし、インストールできないんですね、セキュリティの問題とかいろいろな事情で。
つまり、私がこの記事で書いたコードはそういう閉鎖的な職場では使えません。
しかし、だからといって労働生産性を下げていいというものではなく、むしろそういう職場こそ労働生産性を上げろとさまざまな方面から強く要求されていたりします・・・orz。
ということで、なんとかSeleniumBasicもWebDriverもなしにVBAだけで完結できないかと試行錯誤したのが本日の記事です。
ちなみに、Power Automate Desktopも検討しましたが、その”閉鎖空間”では使えません(ダウンロードさせてもらえません)。Windows11ではなくWindows10なので、プレインストールもされていません。
コード
最初にコードを掲示しておきます。
Option Explicit
'ワークシートに表示する情報のヘッダ
Enum e
出発地 = 1
目的地
時間
距離
TheEnd = 距離
End Enum
'InternetExplorer
Public ie As InternetExplorer
'
'作成:野口香
'作成:2023/04/21
'
Public Sub GetMap()
'作業用シート
Dim sh As Worksheet
Set sh = ThisWorkbook.Worksheets(1)
'InternetExplorerを用意
Set ie = New InternetExplorer
'IE(InternetExplorer)を表示する
ie.Visible = True
'GoogleMapのURLへ遷移
ie.navigate "https://www.google.co.jp/maps/dir///@36.3911651,139.0625882,17.98z/data=!4m2!4m1!3e0"
Call ieWaitTime 'ieの読み込み待ち
'ブラウザを最大サイズに。これをすると手動で元のサイズに戻せない。戻すときはFullScreen = False
'デバッグ中、残ってしまったブラウザを終了させるときはAlt+F4
ie.FullScreen = True
Call ieWaitTime 'ieの読み込み待ち
'前回までの情報をクリアしておく
Const clHeader As Long = 2 'ヘッダ行の行番号
sh.Range(sh.Cells(clHeader + 1, e.時間), sh.Cells(sh.Rows.Count, e.TheEnd)).ClearContents
'Loop開始前、準備
Dim ii As Long, lRow As Long
Const cstStart As Long = 3
lRow = sh.Cells(cstStart, e.目的地).End(xlDown).Row '調査対象のレコード件数を把握する
If lRow = sh.Rows.Count Then '行数が最大値の場合、レコードが1件だけということなので、修正。
lRow = cstStart
End If
Dim el As HTMLInputElement, xp As XPath
Dim bn As HTMLButtonElement, te As HTMLTextElement
Dim html As HTMLDocument
Set html = New HTMLDocument
Set html = ie.document
'Loop突入
For ii = cstStart To lRow
'出発地
Set el = html.querySelector("#sb_ifc50 > input")
Call ieWaitTime 'ieの読み込み待ち
el.Value = sh.Cells(ii, e.出発地).Value
Call ieWaitTime 'ieの読み込み待ち
'目的地
Set el = html.querySelector("#sb_ifc51 > input")
Call ieWaitTime 'ieの読み込み待ち
el.Value = sh.Cells(ii, e.目的地).Value
Call ieWaitTime 'ieの読み込み待ち
el.Focus 'このFocusがないと出発地と目的地のInputTextがdeleteされてしまうので。
'検索ボタンをクリック
Set bn = html.querySelector("#directions-searchbox-1 > button.mL3xi")
Call ieWaitTime 'ieの読み込み待ち
bn.Click
Call ieWaitTime 'ieの読み込み待ち
'Webサイトの表示情報が更新されたので、いったんHtml.documentを取り直す←本来これはいらないはずだけど、次の「時間を取得」のステップでエラーが頻発したので入れてみた。
Set html = ie.document
Call ieWaitTime 'ieの読み込み待ち
'時間を取得
Set te = html.querySelector("#section-directions-trip-0 > div.MespJc > div:nth-child(1) > div.XdKEzd > div:nth-child(1) > span:nth-child(1)")
Call ieWaitTime 'ieの読み込み待ち
sh.Cells(ii, e.時間).Value = te.innerText
Call ieWaitTime 'ieの読み込み待ち
'距離を取得
Set te = html.querySelector("#section-directions-trip-0 > div.MespJc > div:nth-child(1) > div.XdKEzd > div:nth-child(2) > div")
Call ieWaitTime 'ieの読み込み待ち
sh.Cells(ii, e.距離).Value = te.innerText
Call ieWaitTime 'ieの読み込み待ち
Next ii
'終了
ie.Quit
'オブジェクト解放
Set sh = Nothing
Set te = Nothing: Set bn = Nothing
Set ie = Nothing: Set el = Nothing
'終了メッセージ
MsgBox "終了"
End Sub
'読込待ち処理
Public Function ieWaitTime()
'ieがBusy(処理中なら)DoEventsで待機
Do While ie.Busy = True
DoEvents
Loop
'ieがREADYSTATE_COMPLETE(全データ読込完了になるまで)DoEventsで待機
Do While ie.readyState <> READYSTATE_COMPLETE
DoEvents
Loop
'操作が安定するよう念を入れて待機
Application.Wait [Now() + "00:00:01"]
End Function
使い方
参照設定が必要です。Microsoft HTML Object Libraryと、Microsoft Internet Controlsをチェックしてください。
ワークシートはこんな感じです。
シート名は使っていないので何でもよいのですが、シートは必ずブックの先頭に置いてください。
1列目(A列)に出発地、2列目(B列)に目的地を都道府県から入力しておきます。
実行ボタンはフォームで作りました。マクロ「GetMap」を登録しておきます。
ボタンを押してマクロが実行されると、時間と距離の欄にGoogleマップのルート検索から取得した時間と距離がセットされます。
解説
今回のコードは64bitWin10環境でOffice365のExcelで実験しました。Windows11では試していないのですが、多分Windows11ではこのコードは使えないと思います。IEが完全にサポート対象外になっているらしいので。
SeleniumBasicを使えないとなると、どうしてもInternetExplorerを使わざるを得ず、本当は使いたくないのだけど、我慢して使いました。私が使っている環境はまだWindows10が主流なので、今回こんな古~~~い規格でコーディングしてみました^^;
InternetExplorerはDOM 3 XPath を実装していないブラウザのようでして、XPathが使えません。仕方がないので、CSSセレクタを使って実装しました。InternetExplorerだとCSSセレクタを使うときはFindElementByCssではなくquerySelectorを使います。単体だとquerySelector、複数だとquerySelectorAllです。
CSSセレクタだと将来仕様が変わったときに使いものにならなくなってしまうのですけど、それは仕方がありません。今日ご紹介するコードは、今日時点で、なんとか動くものという程度の価値だと思ってください(そもそもInternetExplorerのブラウザとしての寿命はすでに2022年に終わっているし、Googleマップ自体がInternetExplorerを非推奨ブラウザとしているし)。
今回のページですと、この部分↓
図で「41分」と表示されている部分が、動的にセレクタが変わる要素となっていました。
どういうことかというと、ある場合には
section-directions-trip-0 > div.MespJc > div:nth-child(1) > div.XdKEzd > div.Fk3sm.fontHeadlineSmall.delay-medium > span:nth-child(1)
となっているのですけど、ある場合には、
section-directions-trip-0 > div.MespJc > div:nth-child(1) > div.XdKEzd > div.Fk3sm.fontHeadlineSmall.delay-light > span:nth-child(1)
となっていまして、固定ではないってことです。そこで、次のように疑似クラスにしました。
section-directions-trip-0 > div.MespJc > div:nth-child(1) > div.XdKEzd > div:first-child > span:nth-child(1)
同様に、他の要素でもF12の開発者コンソールからとってきたままではなく、ある程度加工して(疑似クラスにして)使っています。疑似クラスについては、こちらのサイトを参考にしました。
https://blog.mrym.tv/2020/07/scraping-sites-with-dynamically-changing-css-selectors/
あとInternetExplorerだとブラウザの読み込みが遅いです。疑似クラスを使っているせいか、それとも要素が読み込みに時間がかかっているのか、毎回同じ個所で落ちます。落ちない場合もあります。
落ちる場所は決まっていて、コードの86行目です。
sh.Cells(ii, e.時間).Value = te.innerText
変数teにうまくHTMLTextElementがSetできていないからのようです。
デバッグ画面でイミディエイトペインにSet文(84行目)をコピペして実行してやればよいです。
これを毎回やるのがおっくうなので、なんとか読み込みサブを複数回入れたり、待ち時間の秒数を延ばしたりしてみたのですけれど、うまくいきません。
一番うまくいった(比較的エラーが減った)のが、現在の形です。処理の直前に、ie.documentを取り直すステップを追加しました(80行目)。これにより、毎回起きていたエラーが10回に1回程度に減ったので、許容範囲かなと思っています。
今回作ったものをZIPにしておいておきます。
https://kn-sharoushi.com/wp-content/uploads/2023/04/20230421geGoogleMapwithoutSelenium.zip
~~~宣伝~~~~
Excel相談では現在無料で相談を受け付けています。すべてのご相談に回答できることは保証できませんが、本日の記事のようなことであれば分かりますので、こういった内容でお困りの場合はお気軽にご相談ください。
メールでのやり取りとなります。また、ご相談内容はブログで紹介されることがありますので、くれぐれも個人情報や機密情報をメールで送らないでください。また、ご相談は匿名でできます。
詳しくはこちら。
-
前の記事
【SeleniumBasic】地図の距離と時間を取得する【Excel】 2023.04.21
-
次の記事
【ExcelVBA】ファイルのタイムスタンプ 2023.04.25