【SeleniumBasic】地図の距離と時間を取得する【Excel】

SeleniumBasic×Excel×Chromeで、Googleマップを検索し、目的地までの距離と時間を取得する方法を紹介します。

本当にやりたいことは別にあるのですが、その前段階として考えました。

Excelシートの例。

このようなExcelシートがあります。出発地と目的地があらかじめ書いてあります。

この二つの地点間の距離と移動にかかる時間をGooglマップからルート検索で取得し、値をワークシートに持ってくるにはどうしたらよいか考えました。

Googleマップ。Googleマップでは地図のキャプチャを利用規約で禁止しているようなので、この図では地図部分にモザイクをかけています。

私が考えたコードはこんな感じです。

Option Explicit
'ワークシートに表示する情報のヘッダ
Enum e
    出発地 = 1
    目的地
    時間
    距離
    TheEnd = 距離
End Enum
'
'作成:野口香
'作成:2023/04/20
'
Public Sub GetMap()
    '作業用シート
    Dim sh As Worksheet
    Set sh = ThisWorkbook.Worksheets(1)
    
    'Seleniumを用意
    Dim driver As Object
    Set driver = CreateObject("Selenium.WebDriver")
    
    'スクレイピングのお作法・・・wait時間
    Const clWAIT As Long = 500
    
    'Chromeをスタート
    driver.Start "Chrome"
    
    'ブラウザを最大サイズに
    driver.Window.Maximize
    
    '前回までの情報をクリアしておく
    Const clHeader As Long = 2
    sh.Range(sh.Cells(clHeader + 1, e.時間), sh.Cells(sh.Rows.Count, e.TheEnd)).ClearContents
    
    'GoogleMapのURL
    Const cstUrl As String = "https://www.google.co.jp/maps/dir///@36.3911651,139.0625882,17.98z/data=!4m2!4m1!3e0"
    driver.Get cstUrl
    driver.Wait clWAIT
    
    '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
        lRow = cstStart
    End If
    
    '出発地
    Dim el As Object
    
    For ii = cstStart To lRow
    
        Set el = driver.FindElementByXPath("//*[@id=""sb_ifc50""]/input")
        el.Clear
        driver.Wait clWAIT
        el.SendKeys sh.Cells(ii, e.出発地).Value
        driver.Wait clWAIT
        
        '目的地
        Set el = driver.FindElementByXPath("//*[@id=""sb_ifc51""]/input")
        el.Clear
        driver.Wait clWAIT
        el.SendKeys sh.Cells(ii, e.目的地).Value
        driver.Wait clWAIT
        
        '検索ボタンをクリック
        driver.FindElementByXPath("//*[@id=""directions-searchbox-1""]/button[1]").Click
        driver.Wait clWAIT * 10 '少し長めに待つ
        
        '時間を取得
        sh.Cells(ii, e.時間).Value = driver.FindElementByXPath("//*[@id=""section-directions-trip-0""]/div[1]/div[1]/div[1]/div[1]/span[1]").Text
        driver.Wait clWAIT
        
        '距離を取得
        sh.Cells(ii, e.距離).Value = driver.FindElementByXPath("//*[@id=""section-directions-trip-0""]/div[1]/div[1]/div[1]/div[2]/div").Text
        driver.Wait clWAIT

    Next ii
    '終了
    driver.Close
    
    'オブジェクト解放
    Set sh = Nothing
    Set driver = Nothing
    Set el = Nothing
    
    '終了メッセージ
    MsgBox "終了"
    
End Sub

実行すると、こんな結果となりました。

実行結果

注意点です。

今回有料道路を使う設定にしてあるので、検索結果には有料道路を利用した場合も出力されています。

有料道路を使わない設定にしたい場合は、チェックボックスをチェックする必要があります(が、今回のコードでは実装していません)。

高速道路を使わないにチェックする

今回コードを実験していて何度かぶつかったのが、要素を特定するXPathにずれがあることです。

出発地のIDを”sb_ifc50“で今回は実装しましたが、”sb_ifc51“となっているブラウザもありました。理由は不明です。Googleアカウントでログインしていると異なる可能性がありますが、未検証です。

使い道としては、大量のリストを渡されたときに、距離と時間から行き先の候補を絞る手助けにできるかと思います。

例では10件程度ですが、私が実際に渡されたのは100件近くありました。さすがにそれを1件ずつ手作業で検索するのは骨が折れますので、VBAで効率よくできないか考えました。

今回作ったものをZIPにしておいておきます。

https://kn-sharoushi.com/wp-content/uploads/2023/04/20230420getGoogleMap.zip

追記

閲覧者の1人から問合せがありまして、2024年5月21日現在、上記コードの72行目部分でエラーになることが確認できています。

原因は、Yahoo!地図サイトのHTML構文が変更になっているためです。

変更前のXPath
//*[@id=”section-directions-trip-0″]/div[1]/div[1]/div[1]/div[1]/span[1]

変更後のXPath
//*[@id=”section-directions-trip-0″]/div[1]/div/div[1]/div[1]

最後の/span[1]がなくなっているようです。

いちいち昔作ったコードを直してあげ直すのも面倒なんで、この記事はこの記事のまま掲載しておきます(後日気が変わって記事を取り下げるかもしれませんが)。

そもそもスクレイピングにおけるエレメント取得は、「あし」(腐る)の早い生物(なまもの)だと思っているので、当時使えたコードが1年も経つと使えないのは仕方がないのかなと個人的には思っています。

どうしても使いたいという方は、72行目を直してから使ってください。その際、IDを囲む””はVBAではダブルで必要になりますので、ご注意を。