【Selenium】Excelから路線検索で交通費を取得する【VBA】
- [記事公開]2023.03.18
- VBA
- ExcelVBA, SeleniumBasic
Yahoo!知恵袋の質問から、ニーズがあるのかもしれないので紹介しておきます。
質問
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10277106315
初心者です。Google Chromを使っています。
エクセルで日付、出発駅、到着駅を入れるとヤフー乗り換えのサイトに飛び、そこからエクセルに料金を転記するコードを作りたいです。
色々調べて作動するところまで確認できたのですが↓、ヤフー乗り換え案内で「日付を入れて検索する」のコードが分かりません。どこに入れたらいいのかも分かりません…有識者の方教えていただけると助かります…お願いいたします。エクセルはこんな状況です↙︎
A B C D E
1 日付 出発地 到着地 片道/往復 料金
2 2023/3/12
3(F列に乗換案内のハイパーリンクのURL)
参考サイト(といってもコピペですが…)は
https://kimoba.com/kasegu/exxcel-vba-ekispart.html を見ました。Sub 交通費()
Dim driver As New Selenium.ChromeDriver
Dim strValue As String
Dim strValueAfter As StringDim intCnt As Integer
Dim intDataCnt As Integer
Dim intFee As IntegerintDataCnt = Worksheets(“交通費自動算出”).Range(“A1”).End(xlDown).Row
For intCnt = 2 To intDataCnt
driver.Get Worksheets(“交通費自動算出”).Cells(intCnt, 6)
strValue = driver.FindElementByXPath(“//*[@id=””rsltlst””]/li[1]/dl/dd/ul/li[2]”).Text
strValueAfter = Replace(strValue, “円”, “”)
Select Case Cells(intCnt, 4).Text
Case “往復”
intFee = Int(strValueAfter) * 2
Case “片道”
intFee = Int(strValueAfter)
Case ElseEnd Select
Worksheets(“交通費自動算出”).Cells(intCnt, 5).Value = intFee
Nextdriver.Close
Set driver = NothingMsgBox “完了しました”
End Sub補足
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10277106315
交通費改定で、毎日参っています。未来の改定後の値段が知りたいため、どうしても日付を入れて検索したいのです…どうかお願いいたします。
質問者さんが参照したサイトはこちら↓です。
https://kimoba.com/kasegu/exxcel-vba-ekispart.html
日付を見ると、2019年なので若干古いです。
回答
上記の質問に対する私の回答がこちら↓
(F列に乗換案内のハイパーリンクのURL)
とありまして、ご紹介のありましたサイトを見ると、F列には長いHyperLink関数を埋め込んでいます。このHyperLink関数を試してみると、現在Yahoo路線で使われているURLより短く、どこか足りないようです(そのため、せっかく日付を入力してあるのにデフォルトで今日の日付しか検索結果に表示しなくなっている)
だから、F列の関数を見直せばよいと思います。
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10277106315
解説
HyperLink関数を直すやり方
質問者さんが参照していた先にあるページを見ると、F列にはHyperLink関数を埋め込むようになっています。
=IF(B2=””,””,HYPERLINK(“https://transit.yahoo.co.jp/search/result?&from=”&ENCODEURL($B2)&”&to=”&ENCODEURL($C2)&”&y=”&TEXT(A2,”YYYY”)&”&m=”&TEXT(A2,”mm”)&”&d=”&TEXT(A2,”dd”)&”&lb=1&type=1&ws=3&s=1&&fl=1&tl=3ticket=ic&expkind=1″))
https://kimoba.com/kasegu/exxcel-vba-ekispart.html
これを実際にExcelのシートに当てはめてみたところ、次のようなURLとなりました。
https://transit.yahoo.co.jp/search/result?&from=%E9%AB%98%E5%B4%8E&to=%E6%9D%B1%E4%BA%AC&y=2023&m=03&d=20&lb=1&type=1&ws=3&s=1&&fl=1&tl=3ticket=ic&expkind=1
HyperLink関数で得られたURL
ところが、これをクリックしてひらいたサイトがこちら↓
3月20日を指定したはずなのに、なぜか3月17日(この実験をした日)になっています。
しかしURL部分を見ると、確かにm=03とかd=20とかの文字が見えています。
おそらくURLが正しくないんだろうなと予想をつけて、手動で正しく検索してみることにしました。
図のように、正しく3月20日の検索結果が得られたところで、URLをコピーして内容を確かめてみます。
https://transit.yahoo.co.jp/search/result?from=%E9%AB%98%E5%B4%8E&to=%E6%9D%B1%E4%BA%AC&fromgid=&togid=&flatlon=&tlatlon=&via=&viacode=&y=2023&m=03&d=20&hh=15&m1=3&m2=5&type=1&ticket=ic&expkind=1&userpass=1&ws=3&s=0&al=1&shin=1&ex=1&hb=1&lb=1&sr=1
正しいURL
先ほどの文字列と比べて、明らかにこちらの方が長いですね。
ということは、サイトにあったHyperLink関数が2019年当時のままで古いのではないかと思いました。
Yahoo!で仕様変更を何度もしているでしょうし、最新の仕様に合わせてHyperLink関数を直してあげればよいのではないかと思います。
私が考えたHyperLink関数はこちら↓です。
=IF(B2=””,””,HYPERLINK(“https://transit.yahoo.co.jp/search/result?&from=”&ENCODEURL($B2)&”&to=”&ENCODEURL($C2)&”&fromgid=&togid=&flatlon=&tlatlon=&via=&viacode=&y=”&TEXT(A2,”YYYY”)&”&m=”&TEXT(A2,”mm”)&”&d=”&TEXT(A2,”dd”)&”&hh=07&m1=3&m2=9&type=1&ticket=ic&expkind=1&userpass=1&ws=3&s=0&al=1&shin=1&ex=1&hb=1&lb=1&sr=1″))
修正後のHyperLink関数
適当に作ったので、いろいろ雑です^^;
個人で楽しむレベルならこの程度でよいと思いますが、仕事でシビアな環境で使うならもう少し汎用的になるように(時刻部分をText関数で編集するとか)修正した方がよいでしょうね。
Seleniumで全部やってしまうやり方
質問者さんの参照していたサイトでHyperLink関数を使う方法が紹介されていましたが、私なら普通に値をちまちま入力していって、検索ボタンをクリックし、検索結果を表示させるだろうなと思いました。せっかくSeleniumを使うんだし、その方が早いと思います。HyperLink関数を使う方法だと、URLの仕様を変えられたらまた修正しないといけないし。
ということで、Seleniumを使って路線検索し、交通費を取得する方法をコードにしてみました。
Option Explicit
Enum c
日付 = 1
発
着
片道往復
交通費
URLPATH
摘要
End Enum
Sub GetFee()
Const clStart As Long = 2 'データが始まる行番号
Dim driver As New Selenium.ChromeDriver
Dim stValue As String
Dim stAfterValue As String
Dim lCnt As Long
Dim lDataCnt As Long
Dim lFee As Long
Dim Sh As Worksheet
Set Sh = Worksheets("交通費自動算出")
lDataCnt = Sh.Range("A1").End(xlDown).Row
Dim lData As Long '日付編集用
For lCnt = clStart To lDataCnt
'Excelシート上から検索対象の日付を把握
lData = Sh.Cells(lCnt, c.日付).Value
'Yahoo路線検索のトップページにアクセス
driver.Get "https://transit.yahoo.co.jp/"
'出発情報
driver.FindElementByXPath("//*[@id=""query_input""]").Clear 'いったんクリアしておかないと追記になる
driver.Wait 100
driver.FindElementByXPath("//*[@id=""query_input""]").SendKeys Sh.Cells(lCnt, c.発).Value
driver.Wait 100
'到着情報
driver.FindElementByXPath("/html/body/div[1]/div[2]/div[2]/div[2]/div[1]/div[1]/div[3]/div[2]/form/dl[2]/dd/input").Clear
driver.Wait 100
driver.FindElementByXPath("/html/body/div[1]/div[2]/div[2]/div[2]/div[1]/div[1]/div[3]/div[2]/form/dl[2]/dd/input").SendKeys Sh.Cells(lCnt, c.着).Value
driver.Wait 100
'日付情報
driver.FindElementByXPath("//*[@id=""y""]").AsSelect.SelectByText Format(lData, "yyyy年")
driver.Wait 100
driver.FindElementByXPath("//*[@id=""m""]").AsSelect.SelectByText Format(lData, "m月")
driver.Wait 100
driver.FindElementByXPath("//*[@id=""d""]").AsSelect.SelectByText Format(lData, "d日")
driver.Wait 100
driver.FindElementByXPath("//*[@id=""searchModuleSubmit""]").Click
driver.Wait 100
stValue = driver.FindElementByXPath("//*[@id=""rsltlst""]/li[1]/dl/dd/ul/li[2]").Text
stAfterValue = Replace(stValue, "円", "")
Select Case Sh.Cells(lCnt, c.片道往復).Text
Case "往復"
lFee = Int(stAfterValue) * 2
Case "片道"
lFee = Int(stAfterValue)
Case Else
End Select
Sh.Cells(lCnt, c.交通費).Value = lFee
Next
driver.Close
Set driver = Nothing
Set Sh = Nothing
MsgBox "完了しました"
End Sub
冒頭のEnumはワークシートの表のヘッダ部分をコピーして、そのままワークシート上で値貼り付けかつ行と列を入れ替えるで貼り付けて作っています。こういう作り方が一番早いし、何よりカラム名を考えなくてよいので楽です。あ、スラッシュ(/)はVBAで使えないので削除しました。URLも予約語っぽいのでURLPATHと少し変えました。
出発情報と到着情報のXPathが、どちらも//*[@id=”query_input”]だったので、出発情報だけにこのXPathを使い、到着情報の方はfull XPathを使いました。
日付情報はSelectリストボックスになっているので、Seleniumの.AsSelect.SelectByTextで値を指定して設定するようにしました。
ボタンをクリックするのは.Clickです。この辺の基本的なメソッドの解説は私はしません。他のすばらしい解説サイトをご参照ください(他力本願)。
あまりにも未来の日付だと選択肢がなくてエラーになりますが、その辺のエラー制御は全く入れていません(デバッグレベルのコードです)。
driver.waitはスクレイピングの作法として入れました。
編集後記
最近Yahoo!知恵袋に寄せられる質問で、余っている質問(回答者数ゼロの質問)が、こういうスクレイピング系の質問ばかりです。
それだけスクレイピングの需要が高いのでしょうか?それとも、回答者たちがスクレイピング系を嫌っているから余っているのでしょうか?
一応ニーズが高いから質問が多いと解釈し、記事にしてみました。
-
前の記事
「真実かつ重大な理由」 2023.03.17
-
次の記事
【就業規則】退職の申出 2023.03.19