質問
2020年12月23日水曜日 6:16
こんなのをVBAで組みました。
Sub TEST()
Dim Driver As New Selenium.WebDriver
With Driver
.Start "chrome"
.Get "[以下略]
End With
End Sub
Chrome画面が出て、すぐに消えてしまうのです。どうしてないのかわからなくて、このフォーラムに質問したところ、ソース冒頭がよろしくないと指摘されました→ https://social.msdn.microsoft.com/Forums/ja-JP/224551c8-5b20-4531-8baa-02f8b96a6d1f/chromevbaseleniumwebdriver?forum=vbajp
具体的にはどういじれば、Chrome画面がすぐに消えてしまう現象を解消できるでしょうか?
すべての返信 (3)
2020年12月23日水曜日 16:33 ✅回答済み
ブラウザーが終了してしまうのは、インスタンス管理の問題ですよね。
解決方法については既に、先の投稿にて gekka さんがサンプルコードを掲載してくださったはず。
具体的にはどういじれば、Chrome画面がすぐに消えてしまう現象を解消できるでしょうか?
既に具体的なコード例付きで提示されているように見えるのですが……どの点が不明だったのでしょうか?
(Selenium に関する質問なのか、そもそも VBA に関する理解度不足ゆえの再質問なのか、判断できませんでした)
分からない点が分からないので、勝手に推察しつつ答えます。
まず、VBA における変数の有効期間については御存知でしょうか。
Sub~End Sub のプロシージャー内で Dim 宣言された変数(ローカル変数)は、プロシージャーの処理が終わったところで、それらの変数が寿命を迎えます。
その変数が WebDriver 型であれば、その変数が保持していた WebDriver のオブジェクトの実態(インスタンス)も、プロシージャー終了時に破棄されることになります。これが、ブラウザーが閉じられてしまう理由です。
一方、プロシージャーの外で宣言された変数(モジュールレベル変数)であれば、アプリケーションが終了するまで残り続けます。そのモジュールがアンロードされたり、明示的に解放したりしない限りはそのままです。
なので今回は、WebDriver はローカル変数で保持せずに、モジュールレベル変数(.NET でいうところのフィールド変数)として保持しておけば良い、ということになります。Sub 内に書かれた「Dim Driver AS WebDriver」を削除して、下記のように変更してみてください。
Option Explicit
Private Driver As WebDriver
もう一つ気になった点。
提示された前質問と今回の質問では
「Dim Driver As New ChromeDriver」
「Dim Driver As New Selenium.WebDriver」
という違いがあったようですが、これは意図的に質問内容を変化させているのでしょうか?
何が分からないのかが分からないので勝手に解説しますが、今回書かれていた
Dim Driver As New Selenium.WebDriver
というコードは、VBA においては、
Dim Driver As Selenium.WebDriver '変数宣言。この時点では Driver の中身は Nothing 状態。
Set Driver = New Selenium.WebDriver 'インスタンスの生成と、それを Driver 変数にセットする処理
という 2 行のコードに相当する処理にあたります。
前者と後者の機能は同じですが、厳密にいえば意味が異なります。
いずれの記述でも動作はするものの、できれば後者の書き方にしておくことをお奨めします。
宣言時に New を付けた場合の振る舞いの違いについては、VBA のドキュメントや下記などをご覧ください。
WebDriver オブジェクトのインスタンス生成に New キーワードを使っていますが、場合によっては CreateObject 関数を使ってインスタンスを生成するケースもあります。(今回は New の方で良いでしょう)
最後に、Selenium.WebDriver と Selenium.ChromeDriver の違いについて。
御存知かもしれませんが、Selenium は 複数のブラウザーをサポートしています。
そして、ブラウザーを制御するために使われるのが WebDriver オブジェクトです。
各メーカーのプリンターごとに、固有のプリンタードライバーがあるように、
それぞれのブラウザーごとに、それぞれ固有の WebDriver の実装があります。
そして SeleniumBasic は、Selenium を Visual Basic (.NET / VBA / VBScript) から呼び出せるようにしたライブラリです。
SeleniumBasic 付属のドキュメントには、基本的に FireFox を前提としたサンプルが書かれています。
たとえばドキュメントの冒頭ページには、下記のようなコードが掲載されていますね。
Set driver = CreateObject("Selenium.FirefoxDriver")
driver.Get "http://www.google.com"
それぞれのドライバーは、共通のインターフェイスを持っています。
そのため、WebDriver 型の変数に対して、それぞれの固有ドライバー型のインスタンスをセットして使うこともできます。
Dim drv As Selenium.WebDriver
' Set drv = New Selenium.ChromeDriver 'Chrome 向け
' Set drv = New Selenium.FirefoxDriver 'Firefox 向け
' Set drv = New Selenium.OperaDriver 'Opera 向け
' Set drv = New Selenium.EdgeDriver 'Edge 向け
Set drv = New Selenium.IEDriver 'Internet Explorer 向け
drv.Start 'ブラウザーを起動
drv.Window.SetPosition 0, 0 '表示位置の指定
drv.Window.SetSize 800, 400 '表示サイズの指定
drv.Get "https://www.google.com/", 30000 '30秒を上限として google ページに遷移させる
上記のように、インタンス生成時にブラウザーを決めることもできますが、
Start メソッドの段階で文字列指定でブラウザーを指定することもできます。
Set drv = New Selenium.WebDriver
' drv.Start "Internet Explorer"
' drv.Start "InternetExplorer"
' drv.Start "IE"
' drv.Start "Firefox"
' drv.Start "FF"
' drv.Start "Opera"
drv.Start "Chrome"
Start メソッドは、0 個~2 個の引数を取ります。
第一引数がブラウザー指定、第二引数がベースURL の指定です。
New あるいは CreateObject でのインスタンス生成時に、汎用の WebDriver ではなく、ChromeBrowser 等のブラウザー固有ドライバーを生成していた場合には、Start メソッドによるブラウザーを指定を省略できます。
2020年12月24日木曜日 2:54
ご教示ありがとうございます。昨日のうちに自力で謎が解けました。
>これは意図的に質問内容を変化させているのでしょうか?
もともとSelenium設定でコードを組んでいました。先に載せたのは、参考にしたあるページにあったものです。載せた後、私の自作のものと設定が違うことに気が付いて、それで再投稿したのです。そして再投稿したものをじーっと眺めているうちに謎が解けました。
ところで実際のソースコードをよろしければ見てもらえますか? 貼り方がよくわからないのですが…
2020年12月24日木曜日 3:28
Option Explicit
Dim Driver As Selenium.WebDriver
'Sleep機能を使うAPI
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
Sub sample()
Set Driver = New Selenium.WebDriver
Driver.Start "chrome"
Dim s As String
Dim Up As String
s = "Hello"
Up = "C:\Users\[省略]\Downloads\DvOjTzdUUAEXjlZ.jpeg"
With Driver
.Get "https://[省略]/ja/users/sign_in"
.FindElementById("user_login").SendKeys "[省略]@gmail.com"
.FindElementById("user_password").SendKeys "[省略]"
.FindElementByName("commit").submit
.Get "https://[省略]"
.FindElementById("question_content").SendKeys (s)
.FindElementById("question_photo").SendKeys (Up)
End With
Sleep (5000)
With Driver
.FindElementById("question_submit").submit
End With
↑こんな感じです。検索し倒して、いろいろなサンプルソースコードから組合わせて作りました。一応こちらの希望する機能を果たしてくれています。しかしもっと磨ける箇所、冗長な箇所がきっとあると思うので、よろしければ指摘してもらえないでしょうか?
[追記]「Sleep」はVBAコードなので「Wait」にすれば Selenium Basic 上で動きますね。↑の投稿後に気が付いて先ほどテストしてみてちゃんと動くことを確認したところです。