VBA技術解説VBAのスクレイピングを簡単楽にしてくれるSelenium
VBAでWebスクレイピングする方法としてIE自動操作がありますが、VBA記述が結構面倒になります、もっと簡単にスマートにVBAを書きたいと思ったら…SeleniumBasicを使ってみましょう。SeleniumBasicは、エクセルVBAでのWeb閲覧を自動化することを強力かつ簡単に実現してくれます。
Windows10で作製したものをずっと使っていたのですが、PCがダメになったのでWin11のPCに移すことにしました。 しかし、エラーで動きません・・・ そうです、「.NET Framework 3.5」が必要だったのです。 この際なので、「TinySeleniumVBA」に変更しようかとも思いましたが、複数ファイルがあり変更するのも面倒なので「.NET Framework 3.5」を入れることにしました。
SeleniumVBA系ツールの変遷VBAでWebブラウザを自動操作するツールの流れは、Google Code上の「Selenium-VBA」プロジェクトから始まったとされています。 ただし、現在の「Selenium Basic」との直接的な継承関係は明確ではありません。 現在の中心となっているのは「Selenium Basic」で、これはWindowsのCOMライブラリとして提供されており、VBAからWebブラウザを操作するための基本的な機能を提供します。 利用にはインストールと参照設定が必要です。
Selenium Basicをベースとして、より使いやすく高機能にした「SeleniumVBA」と呼ばれるツール群やラッパーライブラリが複数開発されています。 これらはアドイン形式での提供や、WebDriverの自動更新機能の追加など、導入の簡易化や機能拡張を目的としています。 一方、全く異なるアプローチとして「TinySeleniumVBA」があります。
現在のVBAによるWebブラウザ自動化の中心は、SeleniumVBAとTinySeleniumVBAの2つになっています。 SeleniumVBAは、Selenium Basicの機能を引き継ぎつつ、より現代的で使いやすい形に発展させたツール群です。WebDriverの自動更新機能やアドイン形式での提供など、実用性を重視した機能拡張が行われています。 TinySeleniumVBAは、純粋なVBAコードのみで実装された軽量版として、インストールや参照設定が不要という利便性で支持を得ています。機能は限定的ですが、制約の多い環境でも導入しやすいという大きなメリットがあります。
SeleniumVBAもTinySeleniumVBAも、基本的な考え方や使い方に極端な差異はありませんので、どれか一つが使えれば、他もつかえると思います。 この記事では「Selenium Basic」だけを記載していますの。 SeleniumVBAとTinySeleniumVBAはそれぞれGitHubリポジトリですので、使いたい場合は別途お調べください。
VBEでの参照設定 参照できているか確認Selenium.には、以下もあります。 ChromeDriver EdgeDriver FirefoxDriver Startメソッドでブラウザを指定するので、とりあえずWebDriverにしておけば良いでしょう。
WEBサイトを表示してみましょう 何はともあれ、お決まりのヤホーを表示してみましょう。 Sub sample() Dim Driver As New Selenium.WebDriver Driver.Start "chrome" Driver.Get "https://www.yahoo.co.jp/" Stop End Sub プロシージャーが終了するとブラウザが閉じてしまうのでStopしています。 ブラウザ起動・終了の定型文としては以下のようにしておけば良いでしょう。 Sub sample() Dim Driver As New Selenium.WebDriver Driver.Start "chrome", "https://www.yahoo.co.jp/" Driver.Get "/" '・・・ Driver.Close Set driver = Nothing End Sub Seleniumの基本的な使い方(株価情報を取得してみる) Yahooを表示したので、 「経済」タブの「日経平均株価」を取得してみましょう。 取得するには、そもそもページ全体の中から、取得したいデータの場所を特定しなければなりません。 WEBページはHTMLで作成されています。 Chromeのデベロッパーツールを使用します。 「Google Chrome の設定」→「その他のツール」→「デベロッパー ツール」 ショートカットは、F12 「デベロッパー ツール」の表示位置は、以下のアイコンで変更できます。 下または右にするのが普通でしょうか。 では、まずはこれを使って、Yahooの「経済タブ」の要素を特定します。このアイコンをクリックすると、要素(element)の選択モードになります。 element選択モードを解除するには、もう一度このアイコンをクリックしてください。 WEBページ内をクリックしても選択モードは解除されます。 element選択モードで、マウスカーソルをWEBページ内で移動すると、
このように、カーソル下が色付けされて表示されるのが分かるようになっています。 適当にカーソルを動かしてみて、色付けされている範囲が変更されることを確認してください。 この色付けされている範囲が、ページを構成している要素(element)になります。
このエレメントは入れ子になっていて、 エレメントの中にエレメントがあり、そのエレメントの中にもさらにエレメントが入っている作りになっています。 上図のように、「経済」が選択された状態でクリックすると、 「デベロッパー ツール」内の該当箇所が選択されます。 今度は、「デベロッパー ツール」内でマウスを移動させてみてください。 「デベロッパー ツール」のマウスカーソル位置に該当するWEBページの当該箇所が色付けされます。 element選択モードで、WEBページ内から目的の箇所を探したり、 デベロッパー ツール内の選択から目的の箇所を探したりと、双方向で探すことができます。 目的のエレメントに到達したら、デベロッパー ツールのelementを右クリックします。そして、「Copy」から「Copy selecter」をクリックしてください。 クリップボードに、CSSセレクターが入ります。 「経済」タブは、 #economy とコピーされたはずです。 これを使って、seleniumで「経済」タブをクリックしてみましょう。
前出のコードに追記します。 エレメントを見つけるので、Find○○というメソッドになります。.FindElementByClass .FindElementByCss .FindElementById .FindElementByLinkText .FindElementByName .FindElementByPartialLinkText .FindElementByTag .FindElementByXPath
いろいろなメソッドが用意されていることを確認しておきましょう。 どれを使うかは、その時々で変わってきますが、 今回は、CSSセレクターなので、 FindElementByCss これになります。 この引数に先ほどCopyしたCSSを入れます。 そして、それをクリックなので、Clickメソッドを使用します。 Sub sample() Dim Driver As New Selenium.WebDriver Driver.Start "chrome", "https://www.yahoo.co.jp/" Driver.Get "/" Driver.FindElementByCss("#economy").Click Stop '確認するため Driver.Close Set Driver = Nothing End Sub これで「経済」タブが表示されたので、クリック→elementを右クリック→Copy selector #economyfb > div.topicscatch > div > dl > dd:nth-child(2) これがコピーされますので、これを使って、
Sub sample() Dim Driver As New Selenium.WebDriver Driver.Start "chrome", "https://www.yahoo.co.jp/" Driver.Get "/" Driver.FindElementByCss("#economy").Click Dim txt As String txt = Driver.FindElementByCss("#economyfb > div.topicscatch > div > dl > dd:nth-child(2)").Text Debug.Print txt Driver.Close Set Driver = Nothing End Sub もうお分かりいただけると思います。 文字列を取得するのですから、Textメソッドを使用します。 結果は、イミディエイトに、 22,258.73 このように表示され、ブラウザも閉じられます。 (当たり前すぎますが、株価は実行日によって変わりますよ。) 色々なパターンでのseleniumの使い方 画面最大化 Driver.Window.Maximize ブラウザで見えていないエレメントにはアクセスできないページもあるので、 最大化しておいた方がとりあえずは扱いやすいと思います。 Wait処理 Driver.Wait ミリ秒Seleniumは、画面が表示されるまで自動で待ってから戻ってくるので、ページロード待ちはあまり気にする必要はありません。 なのですが、それだけでは対応できないページもあります。 といいますか、結構多いです。 そこで、ページによっては明示的にwaitを入れる必要が出てきます。
必要なエレメントが見つかるまでループさせる方法にしたほうが良いのですが、 単純に、1~3秒程度待たせてしまったほうが、VBA自体は簡単になります。 テキストボックスに文字を入れる Sub sampla1() Dim Driver As New Selenium.WebDriver Dim sKey As New Selenium.Keys Dim elm As Selenium.WebElement Driver.Start "chrome", "https://www.google.co.jp/" Driver.Get "/" Set elm = Driver.FindElementByXPath("//*[@id=""tsf""]/div[2]/div/div[1]/div/div[1]/input") elm.Clear elm.SendKeys "エクセルの神髄" elm.SendKeys sKey.Enter Stop '確認 Driver.Close Set Driver = Nothing End Sub ここではVBAサンプルとして、Googleで「エクセルの神髄」を検索しています。 エレメント検索のバリエーションとしてXPathをにしています。また、サンプルとしてエレメントをオブジェクト変数にセットするようにしています。 文字列の送信は、SendKeysになりますが、 既に文字が入っている場合はその後ろに入ってしまうので一旦Clearするようにしています。
ドロップダウン(プルダウン)メニューの選択 AsSelectメソッドを使います。 Driver.FindElementByCss(css文字列).AsSelect.SelectByText "値" Driver.FindElementByCss(css文字列).AsSelect.SelectByIndex 2 上記のほか、SelectByValueやSelectByOptionもあります。 フレームを切り替える iframeタグが使われているページの場合、各iframe内の要素にはそのままではアクセスできません。 iframeは「inline frame」の略で、インラインのフレームを作成するためのタグです。 HTMLは以下のようなものになります。 iframe内の要素にアクセスするには、その前に当該のiframeに切替てから行います。 Driver.SwitchToFrame "identiFier" iframe内に切り替えた後は、普通にFindElement○で要素を取得できます。 色々組み合わせて目的の画面にたどり着きます Yahooで以下の操作を行います。 「経済」→「日経平均株価」→「銘柄コード」に4689→「検索」→「アラート設定」 →「ID」入力→「次へ」→「パスワード」入力→「次へ」→「値上がり率」に15%Sub sample2() Dim Driver As New Selenium.WebDriver Dim elm As Selenium.WebElement Driver.Start "chrome", "https://www.yahoo.co.jp/" Driver.Get "/" Driver.Window.Maximize '「経済」 Driver.FindElementByCss("#economy").Click '「日経平均株価」 Driver.FindElementByCss("#economyfb > div.topicscatch > div > dl > dt:nth-child(1) > a").Click '「銘柄コード」に4689 Driver.FindElementByCss("#searchText").SendKeys "4689" '「検索」 Driver.FindElementByCss("#searchButton").Click '「アラート設定」 Driver.FindElementByCss("#settings > span.alerts > a").Click '「ID」入力 Driver.FindElementByCss("#username").SendKeys "ID" '「次へ」 Driver.FindElementByCss("#btnNext").Click '「パスワード」入力:そのまま続けるとエラーとなるのでWait対応 Set elm = WaitForElement(Driver, "#passwd") If elm Is Nothing Then MsgBox "「#passwd」見つかりません。" End End If If Not WaitForSendKeys(Driver, elm, "パスワード") Then MsgBox "パスワードを入力できませんでした。" End End If '「次へ」 Driver.FindElementByCss("#btnSubmit").Click '「値上がり率」に15% Driver.FindElementByCss("#up_0").AsSelect.SelectByText "15%" Stop '確認 Driver.Close Set Driver = Nothing End Sub
Function WaitForElement(ByVal Driver As WebDriver, ByVal sCss As String) As Selenium.WebElement Dim cnt As Long On Error Resume Next Do cnt = cnt + 1 Set WaitForElement = Driver.FindElementByCss(sCss) If Not Err Then Exit Function End If Driver.Wait 100 If cnt > 100 Then Exit Do Loop Set WaitForElement = Nothing End Function
Seleniumでブラウザを起動すると、 クッキー等は全て無効になっているので画面によっては、通常操作では必要ないログインを求められます。Yahooのこのページでは、パスワード入力がそのままではエラーとなってしまいます。 1秒程度のWaitで問題なく進めますが、 上記ではサンプルの意味も兼ねて、エレメントへの設定が正しく行われるまで繰り返すようにしています。
最後のドロップダウンのoptionを確認する場合、 デベロッパーツールで、ドロップダウンをクリック後に、 "down_0>…この…をダブルクリッククリックすると、optionの中が展開されます。 elementをコレクションで取得する tdタグやliタグのように、同一タグの繰り返しを順次処理する場合は、 指定タグのエレメントをコレクションで取得し、For~Eachで処理します。 以下では、Yahooのトピック一覧を取得しています。 Sub sample4() Dim Driver As New Selenium.WebDriver Dim elm1 As Selenium.WebElement Dim elm2 As Selenium.WebElement Driver.Start "chrome", "https://www.yahoo.co.jp/" Driver.Get "/" Set elm1 = Driver.FindElementByCss("#topicsfb > div.topicsindex > ul.emphasis") For Each elm2 In elm1.FindElementsByTag("li") Debug.Print elm2.Text Next Driver.Close Set Driver = Nothing End SubFind○○メソッドには、オブジェクト単体の取得とコレクションの取得が用意されています。 FindElementとFindElement s が存在します。 コレクションとして取得する場合は、FindElement s を使用します。
.FindElementsByClass .FindElementsByCss .FindElementsById .FindElementsByLinkText .FindElementsByName .FindElementsByPartialLinkText .FindElementsByTag .FindElementsByXPath
新規ページが開かれる場合 クリックによって新規ページが開かれるような場合、新規ページへ移動する必要があります。 まずは特に何もしない場合の動作状況になります。 Sub sample3() Dim Driver As New Selenium.WebDriver Driver.Start "chrome" Driver.Get "https://excel-ubara.com/EXCEL/EXCEL918.html" Driver.FindElementByLinkText("Excelシートの複雑な計算式を解析するVBAの関数構文").Click Debug.Print Driver.FindElementByTag("h1").Text Stop '確認 Driver.Close Set Driver = Nothing End Sub これでイミディエイトに出力されるのは、 「VBAリファレンス Excelワークシート関数一覧(2010以降)」 このように、クリックする前の元のページのh1が取得されてしまいます。 そこで、次のウィンドウへ移動する必要があります。 Sub sample3() Dim Driver As New Selenium.WebDriver Driver.Start "chrome" Driver.Get "https://excel-ubara.com/EXCEL/EXCEL918.html" Driver.FindElementByLinkText("Excelシートの複雑な計算式を解析するVBAの関数構文").Click Driver.SwitchToNextWindow Debug.Print Driver.FindElementByTag("h1").Text Driver.Close Set Driver = Nothing End Sub これでイミディエイトに、以下のように出力されます。 「ExcelマクロVBAサンプル集 Excelシートの複雑な計算式を解析するVBAの関数構文」 複数開いている場合は、タイトルを保存しておいて、 Driver.SwitchToWindowByTitle "タイトル" これで移動可能です。以下のようなVBAコードを追加して、画面遷移を確認してみると良いでしょう。 Debug.Print "1:" & Driver.window.Title Driver.SwitchToNextWindow Debug.Print "2:" & Driver.window.Title Debug.Print Driver.FindElementByTag("h1").Text
上手くいかない特殊な場合の対処方法実際のWEBページは多種多様で、ここまでの対処できない場合が多々あります。 そのような場合は、個別の対処方法を考える必要があります。 以下に代表的な対処方法の例を載せておきます。 あくまで一例ですので、使う場合は個別に工夫してお使いください。
※以下では、Driverはモジュールレベルで宣言されているものとしています。 テキストボックスに1回で文字列を入れられない場合Dim t As Double t = Timer Do Driver.FindElementByCss(sCss).Clear Driver.FindElementByCss(sCss).SendKeys argText If Driver.FindElementByCss(sCss).Value = argText Then Exit Do If Timer > t + maxTime Then Exit Function Driver.Wait waitTime Loop
クリック後に新ページ移動前にseleniumから戻ってきてしまう場合Dim sUrl As String Dim t As Double t = Timer
sUrl = Driver.Url Do Driver.FindElementByCss(sCss).Click If sUrl Driver.Url Then Exit Do If Timer > t + maxTime Then Exit Function Driver.Wait waitTime Loop
画面ロード完了前にseleniumから戻ってきてしまう場合Dim t As Double t = Timer
Dim elms As Selenium.WebElements Do Set elms = Driver.FindElementsByCss(sCss) If elms.Count > 0 Then Exit Do If Timer > t + maxTime Then Exit Function Driver.Wait waitTime Loop
遷移後のURLに直接移動する Driver.Get Driver.Url & "?xxx&yyy" 最後の手段になりますが、遷移後のURLに移動してしまう方法も結構有効です。 クリック後にURLパラメーターが追加になるような場合は、直接パラメーターを追加したURLを指定してしまう方法になります。 元々のURLの最後が"/"で終わっているか、既に"?"が入っているか、 これらの状態によって、追加するパラメーターは適宜変更が必要になります。 URLに付け加える変数です。 クエスチョンマーク"?"をURLの末尾に付け、「変数(パラメータ)=値」の形式で指定します。 複数のパラメーターはアンパサンド(&)でつなげます。 Seleniumの実践例例 ここで紹介したテクニックを使い、キーワードを指定してGoogleの検索順位を取得しています。 VBA+SeleniumBasicで検索順位チェッカー作成 ・シート構成 ・検索順位チェッカーのVBA全コード ・最後に VBA+SeleniumBasicで検索順位チェッカー(改) ・シート構成 ・検索順位チェッカーのVBA全コード ・最後に 最後に今まで筆者はSeleniumVBAを使っていたのですが、SeleniumBasicではメソッドが結構変更になっていました。 実際に動作確認しながら本記事を書きましたが、細部においてはより効率的な使い方があるかもしれません。 ただし全体的には、SeleniumVBAより使いやすくなっているように感じました。
クローリング&スクレイピングは、サイトごとのクセを見極めることが面倒な作業になります。 特にJavaScriptでマウスオーバーにより切り替わるような場合はかなり面倒です。 SeleniumでJavaScriptのコードを実行(.ExecuteScript)することもできますが、 このようなサイトでは、結構頻繁にサイトが更新されてしまう為になかなか安定運用できない場合が多いようにも思われます。
いずれにしても、クローリング&スクレイピングではサイト変更によってVBAを変更しなければならないものです。 従って、いつでも簡単にVBA修正して運用できる環境であることが望まれます。 もし、そのような運用が難しい場合(開発会社に依頼して作ってもらう等の場合)は、 サイト変更時の対応を事前に良く確認しておくことをお勧めします。
同じテーマ「マクロVBA技術解説」の記事 新着記事 NEW ・・・新着記事一覧を見る アクセスランキング ・・・ ランキング一覧を見る このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。 掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。 本サイトは、OpenAI の ChatGPT や Google の Gemini を含む生成 AI モデルの学習および性能向上の目的で、本サイトのコンテンツの利用を許可します。 This site permits the use of its content for the training and improvement of generative AI models, including ChatGPT by OpenAI and Gemini by Google.