Excel VBAでFirefoxを操れる素晴らしいツール。それがSeleniumbasic。
以前はSeleniumVBAという名称だったが、昨年秋ごろにSeleniumBasicに変わった。今後SeleniumVBAの方はメンテされないそうなので注意。
インストール
ダウンロードページからインストーラをダウンロードして実行する。2016年2月2日現在はSeleniumBasic-2.0.7.0.exe。インストール先は%LOCALAPPDATA%\SeleniumBasic。
インストーラの最後に、Firefoxアドオンを入れるかどうか聞かれる。これを入れておくと、Firefoxの操作を記録してコードをエクスポートすることができる(Excelのマクロ記録に近い感じ)。だけど、私は今のところ使っていないなあ。
Excelを起動し、ツールの参照設定でアドオンを有効にする。
Fig.1 参照設定でSelenium Type Libraryを有効化 |
オブジェクトを宣言する
以下を標準モジュールのどっかに書いておけばOK。Public driver As New WebDriver Public keys As New keys Public by As bySeleniumBasicには他にも色々なクラスがあるが、Firefox自動操作には取り急ぎ上記3種類があれば十分ではないかと思う。
Firefoxを起動する
まず真っ先にやることは、Firefoxを起動すること。(起動済みのFirefoxを使い回す方法もある。後ほど。)
driver.Start "firefox", "https://dsp74118.blogspot.jp/" driver.Get "/"
要素にアクセスする
WebDriverクラスにはFindElement(s)ByXXXXというメソッドが用意されてる。これは、JavaScriptやInternetExplorerオブジェクトにおけるdocument.getElement(s)ByXXXに相当する。 大体メソッド名で使い方は想像できると思う。Fig.2 WebDriverクラスのメンバー |
Dim elm as Object set elm = driver.FindElementById("id1")という感じで、DOMオブジェクトを変数に格納できる。
要素内のテキストを取得する
以下の様な感じで、id="id1"の要素のinnerTextを取得できる。str = driver.FindElementById("id1").TextinnerHTMLを取得する方法は無いっぽい?誰か知ってたら教えて下さい。
テキストボックス等に文字を入力する
SendKeysメソッドを使う。driver.FindElementByName("text1").SendKeys "みょみょみょ"既に値が入っている場合は、1回clearをする。clearしないと、元から入っていた値の後ろに追記されてしまう。
InternetExplorerオブジェクトを使ってIEを自動操作する際には、DOMオブジェクトのvalueプロパティに値を入れるだけで、元の値を上書きしてくれるのだけど。ここは対照的。
driver.FindElementByName("text1").Clear driver.FindElementByName("text1").SendKeys "abc"keysクラスを使えば特殊キーも送れる。下記は一例。
driver.FindElementById("text2").SendKeys keys.Control, "a" driver.FindElementById("text2").SendKeys keys.Delete
要素の存否確認
要素が存在しない時に、FindElementByXXXシリーズで要素にアクセスするとエラーで落ちちゃう。 例えば、name="name1"の要素が存在しない時にdriver.FindElementByName("name1")ってやるとエラーになる。そのため、要素があるかどうか不確定の時は、事前に存否確認をする必要がある。
で、IsElementPresentというメソッドで、DOM内に特定の要素があるかどうか調べることができる。
第一引数には、by.Idとか、by.Nameとかがある。
…はずだったが、私の環境では動いたり動かなかったりする! なんで?
If driver.IsElementPresent(by.name("name2")) Then 'expect True of False
Fig.3 IsElementPresentが動かない... |
仕方がないので
if driver.FindElementsByName("name3").Count > 0 Thenとやってる。かっこわる。
あ、FindElementsByXXXシリーズ(sが入ってる)は、要素がなくてもエラーになりません。
x番目の要素を取り出す
HTML内のx番目のtableのy行目のz列目のテキストを取り出すなら、xyzText = driver.FindElemntsByTag("table")(x).FindElementsByTag("tr")(y).FindElementsByTag("td")(z).Textとやる。
同様に、ページ内の特定のボタンやラジオボタン、チェックボックスをクリックしたい時は、
driver.FindElementsByTag("input")(x).Clickとできる。
全input要素にidがついていれば、FindElementByIdで要素を特定すればよいが、世の中そうでない場合も多々あるので…。
全部の要素にアクセスするなら、forでループさせる。
Dim tags As Object, tag As Object Set tags = driver.FindElementsByTag("a") For Each tag In tags MsgBox tag.Text NextCountプロパティで数を調べてループする方法も使える。
Dim tags As Object, i as Integer Set tags = driver.FindElementsByTag("a") For i = 1 To tags.Count MsgBox tags(i).Text Next2番目以降の要素にだけアクセスしたいときは後者が便利(例えばtableの1行目がタイトル行になってて、2行目以降のデータだけ取り出したい時とか)
特定のリンク先をクリックする
XPathは個人的には嫌いだが使う。以下のような感じで、好きな要素(特定のattributeを持つ要素とか)を狙い撃ちできる。href="../hogehoge.html" driver.FindElementByXPath("//a[@href='" & href & "']").Clickどんな時に役立つかというと、私は上記のようにaタグを特定する時に使っている。特に、onClickで何かしてるリンクをクリックする時に便利だと思う。
多分
onClickString = "javascript:hoge()" driver.FindElementByXPath("//a[@onclick='" & onClickString & "']").Clickとかもできる。試してないけど。
プルダウンメニューを選択する
AsSelect.SelectByXXX メソッドを使う。<select name="select1"> <option value="value1">text1</option> <option value="value2">text2</option> </select>こんなプルダウンがある時に、option内のtextでプルダウンを選択するなら
driver.FindElementByName("select1").AsSelect.SelectByText ("text1")optionのvalueが分かっているなら、以下の方法も使える。
driver.FindElementByName("select2").AsSelect.SelectByValue ("value1")
プルダウンメニューの中身を取り出す
以下の様な感じで、プルダウンメニューのi番目のoptionのtextが取り出せる。なぜかOptions(i)ではダメ。
optionText = driver.FindElementByName("select3").Options.Item(i).Text
属性(attribute)
以下の様な感じでattributeを取り出せる。"getAttribute"と間違えがちなので注意。
href = driver.FindElementByName("a").Attribute("href")
一度開いたFirefoxのウインドウを使い回す
Seleniumというツールは、処理を走らせるたびにブラウザを開いて、処理が終わったら閉じる、という使い方を想定しているっぽい節がある。が、処理のオートメーションという要件からすると、ログインが必要なWebページで同じような処理を繰り返し行いたい場合だってある。そんなケースで、1回処理を流すたびにブラウザが開いて、ログインして、処理して、ログアウトして、ブラウザ閉じる…という動作をしていたら、まどろっこしくて仕方がない。ここは、一度開いたブラウザを、ログインしたままキープして使い回したいところ。今のところ、下記のような関数で、この要件を実装している。
以下のコードはサンプルなので、私が実際に使っているものとは少し変えてある。
(IDとパスワードがベタ書きになってるとことか。)
Public driver As New WebDriver ' Firefoxで某システムを開く ' - Firefox未起動だったら起動し、某システムのログイン画面を表示して自動ログイン ' - Firefox起動済みで、どこか他所のドメインに移動してたら、某システムのトップページに戻る ' - Firefox起動済みでログイン済みだったら何もしない ' - Firefox起動済みでセッションが切れてたら自動再ログイン ' @return 失敗したらfalse Public Function OpenExampleCom() As Boolean Dim winCount As Integer Dim errNum As Integer OpenExampleCom = False On Error Resume Next winCount = driver.Windows.Count errNum = Err.Number On Error GoTo 0 ' ToDo この辺りの処理は精査必要? If errNum = 57 Or winCount = 0 Then ' Firefoxを起動して、ページを開く driver.Start "firefox", "http://example.com/" driver.Get "/login" ' ログイン If AutoLogin = False then GoTo finally End If Else If driver.baseUrl <> "http://example.com" Then ' baseUrlが変わってたらセットし直し、トップページに移動。 driver.baseUrl = "http://example.com/" driver.Get "/topPage" End If ' セッション判定 ' ログアウトorタイムアウト画面ならログイン画面に移動。 ' 対象のページに合わせて適切に書き換えること。 If driver.FindElementByTag("h1").Text = "Logout" Or _ driver.FindElementByTag("h1").Text = "TimeOut" Then driver.Get "/login" End If ' 今いるのがログイン画面ならログインする。 If AutoLogin = False then GoTo Finally End If End If OpenExampleCom = True finally: ' 事後処理。何かあればここに書く。 End Function ' 自動ログイン ' @return 失敗したらfalse Private Function AutoLogin() as Boolean AutoLogin = True ' 今いるのがログイン画面ならログイン処理を行う。 ' 対象のページに合わせて適切に書き換えること。 If driver.FindElementByTag("h1").Text = "Login" Then driver.FindElementById("userid").SendKeys "dsp74118" driver.FindElementById("passwd").SendKeys "Password" driver.FindElementByTag("input").submit ' ログイン成否判定。対象のページに合わせて適切に書き換えること。 If driver.FindElementByTag("h1").Text = "Login Error" Then MsgBox "ログインに失敗しました。" AutoLogin = False End If End If End Function続きがあります。
すごいです。
返信削除勉強になります。
Casino Review and Bonus Code - JTHub
返信削除Casino Bonus 전주 출장안마 Codes — All the 광주광역 출장안마 Casino players can choose 서산 출장마사지 to 경상북도 출장안마 play at JTRCasino. The game offers a generous welcome bonus of $5,000 and 고양 출장안마 a