C# + Selenium + ChromeDriverを使って、HTMLフォームへ入力することがあったため、メモを残しておきます。
環境
- Windows10
- Git for Windows
- Visual Studio 2015 Community
- .NET Framework 4.6.1
- Chrome Driver 2.20
- SeleniumまわりのNuGetパッケージ
- Seleniumの対象とするWebアプリ
- 以下のPytnon + Djangoアプリを想定
準備
Python + Djangoアプリの準備
GitHubからclone・セットアップし、アプリを起動しておきます。
>cd path\to\dir # GitHubからカレントディレクトリへclone path\to\dir>git clone https://github.com/thinkAmi-sandbox/Django_form_sample.git . # virtualenv環境の作成とactivate path\to\dir>virtualenv -p c:\python34\python.exe env path\to\dir>env\Scripts\activate # requirements.txtよりインストール (env)path\to\dir>pip install -r requirements.txt # マイグレーションと初期データ投入 (env)path\to\dir>python manage.py migrate (env)path\to\dir>python manage.py loaddata initial_data # 開発サーバの起動 (env)path\to\dir>python manage.py runserver # 開発サーバのURLを既定のブラウザで開く # (別のコマンドプロンプトを開いて実行) >start http://localhost:8000/site/register
起動したWebアプリのフォームは以下の通りです。
ブラウザ画面
HTMLソース
<!DOCTYPE html> <html lang="ja" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title>My Site</title> </head> <body> <div id="main"> <form method="post" action="" name="detail"> <fieldset> <input type='hidden' name='csrfmiddlewaretoken' value='ikcYFvPfvvYuXlhdIrDN1t80ejAleTOH' /> <p> <label for="id_registration_date">RegistrationDate:</label> <input id="id_registration_date" name="registration_date" type="date" value="2016-01-12" /> <input id="initial-id_registration_date" name="initial-registration_date" type="hidden" value="2016-01-12 13:02:15+00:00" /> </p> <p> <label for="id_pushed_0">Pushed:</label> <ul id="id_pushed"> <li> <label for="id_pushed_0"> <input id="id_pushed_0" name="pushed" type="radio" value="1" />radio1 </label> </li> <li> <label for="id_pushed_1"> <input id="id_pushed_1" name="pushed" type="radio" value="2" />radio2 </label> </li> <li> <label for="id_pushed_2"> <input id="id_pushed_2" name="pushed" type="radio" value="3" />radio3 </label> </li> </ul> </p> <p> <label for="id_checked">YesNo:</label> <input id="id_checked" name="checked" type="checkbox" /> </p> <p> <label for="id_checked_multiple_0">CheckdMultiple:</label> <ul id="id_checked_multiple"> <li> <label for="id_checked_multiple_0"> <input id="id_checked_multiple_0" name="checked_multiple" type="checkbox" value="1" />checkbox1 </label> </li> <li> <label for="id_checked_multiple_1"> <input id="id_checked_multiple_1" name="checked_multiple" type="checkbox" value="2" />checkbox2 </label> </li> <li> <label for="id_checked_multiple_2"> <input id="id_checked_multiple_2" name="checked_multiple" type="checkbox" value="3" />checkbox3 </label> </li> </ul> </p> <p> <label for="id_selected">Selected:</label> <select id="id_selected" name="selected"> <option value="" selected="selected">---------</option> <option value="1">select1</option> <option value="2">select2</option> <option value="3">select3</option> </select> </p> <p> <label for="id_selected_multiple">SelectedMultiple:</label> <select multiple="multiple" id="id_selected_multiple" name="selected_multiple"> <option value="1">select_multi1</option> <option value="2">select_multi2</option> <option value="3">select_multi3</option> </select> </p> <p> <label for="id_input_text">InputText:</label> <input id="id_input_text" maxlength="255" name="input_text" type="text" /> </p> <p> <label for="id_text_area">TextArea:</label> <textarea cols="40" id="id_text_area" name="text_area" rows="10"></textarea> </p> <input type="submit" id="save" value="Save"> </fieldset> </form> </div> </body> </html>
C#のプロジェクト作成
今回はコンソールアプリとして作成します。
NuGetパッケージのインストール
以下の2つのNuGetパッケージをインストールしておきます。
Selenium用Chrome Driverのダウンロード
Chrome Driver(chromedriver_win32.zip
)を以下よりダウンロードします。
ChromeDriver - WebDriver for Chrome
その後、
- zipファイルを解凍
- 解凍したディレクトリにある
chromedriver.exe
ファイルを、コンソールアプリプロジェクトへ追加 - ファイルのプロパティで、
出力ディレクトリにコピー
の値を常にコピーする
へと変更
を行います。
Seleniumを使ったフォームへの入力など
ChromeDriverの利用
ChromeDriverはIDisposable
インタフェースを実装しているため、using
ステートメントを使えます。
この場合、実行後にChromeが自動終了してしまうため、コマンドプロンプトにて入力待ちを実装しておきます。
また、driver.Navigate().GoToUrl()
を使って、対象のフォーム画面へと遷移します。
using (var driver = new OpenQA.Selenium.Chrome.ChromeDriver()) { driver.Navigate().GoToUrl("http://localhost:8000/site/register/"); // 自動終了しないようにする Console.WriteLine("何かキーを押すことで終了します"); Console.ReadKey(); }
<input type="text">
と<textarea>
両方とも、SendKeys()
で設定、Clear()
でクリアします。
var element = driver.FindElement(OpenQA.Selenium.By.Id("id_input_text")); // <input type="text">へデータを設定 // なお、既にデータがあったり複数回の入力の場合、 // データは追記されていく element.SendKeys("テキスト"); element.SendKeys("txt"); // <input type="text">のデータ削除 element.Clear();
<input type="date">
SendKeys()
で設定・クリアなどを行います。
以下を参考に実装しましたが、色々と手間があるため、もしかしたら他に良い方法があるかもしれません。
- Handling Date Time Picker using Selenium
- time - Clear date input fails on chromewebdriver - Stack Overflow
var element = driver.FindElement(OpenQA.Selenium.By.Id("id_registration_date")); // <input type="date">へデータを設定 // デフォルトでは本日日付が入っているWebアプリなので、 // 年月日いずれも1つ前のデータを入力してみる var inputDate = DateTime.Now.AddYears(-1).AddMonths(-1).AddDays(-1); // ChromeDriverの場合、 // 年の位置にカーソルがある状態で、 // 年6桁・月2桁・日2桁という各桁数を持つ、 // 前ゼロ詰め数字を入力すると、 // 既存の値を上書きして設定される // *`2016/01/01`や`2016-01-01`ではうまく設定できず var year = string.Format("{0:D6}", inputDate.Year); var month = string.Format("{0:D2}", inputDate.Month); var day = string.Format("{0:D2}", inputDate.Day); element.SendKeys(year + month + day); // 後続の処理のために: // この時点ではカーソルが`日`の位置にあるため、 // driver.FindElement()した時のカーソル位置(`年`)へ戻す // なお、Keysを連結して.SendKeys()に渡した場合、 // 連結したキーをすべて含む動作をしてくれる element.SendKeys(Keys.ArrowLeft + Keys.ArrowLeft); // <input type="date">のデータ削除 // ChromeDriverの場合、.Clear()ではエラーになる // invalid element state: Element must be user-editable in order to clear it. //element.Clear(); // そのため、.SendKeys()でDeleteキーを使って削除する // ただ、Deleteキーを1回押すだけでは`年`だけが消えるので、カーソルキーを併用して // 1回目:年、2回目:月、3回目:日をそれぞれ消す for (int i = 0; i < 3; i++) { element.SendKeys(Keys.Delete); element.SendKeys(Keys.ArrowRight); } // データ削除したところに再入力する場合は、 // 年の位置へカーソルを戻してから、再度入力する element.SendKeys(Keys.ArrowLeft + Keys.ArrowLeft); var reInputDate = DateTime.Now.AddYears(1).AddMonths(1).AddDays(1); var reYear = string.Format("{0:D6}", reInputDate.Year); var reMonth = string.Format("{0:D2}", reInputDate.Month); var reDay = string.Format("{0:D2}", reInputDate.Day); element.SendKeys(reYear + reMonth + reDay);
<input type="date / radio / checkbox">
いずれもelementをClick()します。
var element = driver.FindElement(OpenQA.Selenium.By.Id("id_pushed_1"));
element.Click();
<select> / <select multiple="multiple">
SELECT要素の選択を行うには、Selenium.Support
パッケージのUI.SelectElement
を使います。
How to Using Webdriver Selenium for selecting an option in C#? - Stack Overflow
以下は <select multiple="multiple">
ですが、両方とも同じような書き方です。
var element = driver.FindElement(By.Id("id_selected_multiple")); var selectElement = new SelectElement(element); // 全部を選択 selectElement.SelectByValue("1"); selectElement.SelectByValue("2"); selectElement.SelectByValue("3"); // 一部を解除 // 選択と同様、Index, Value, Textの3種類あり selectElement.DeselectByValue("2"); // もしくは、一括で解除 selectElement.DeselectAll();
フォームのSubmit
Submit
が用意されています。
var element = driver.FindElement(By.Id("save"));
element.Submit();
スクリーンショットを撮る
フォームとは関係ありませんが、スクリーンショットを撮る方法も載せておきます。
var s = ((OpenQA.Selenium.ITakesScreenshot)driver).GetScreenshot(); s.SaveAsFile(System.IO.Path.Combine( System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), @"selenium.jpg"), System.Drawing.Imaging.ImageFormat.Jpeg);
なお、以下のstackoverflowでは各言語のスクリーンショットの撮り方が記載されています。
Take a screenshot with Selenium WebDriver - Stack Overflow
ソースコード
今回使用したC#のコンソールプロジェクトは、GitHubに上げておきました。
SeleniumSampleUsingCsharp/InputFormRunner at master · thinkAmi-sandbox/SeleniumSampleUsingCsharp
参考
APIドキュメント
SeleniumHQ/selenium - GitHubに、C#のAPIドキュメントへのリンクがありました。フッターには2013とありますが、たぶん大丈夫でしょう...
WebDriver - Table of Content