1. yk109

    Posted

    yk109
Changes in title
+SeleniumのChromeDriverで起動済みのブラウザを操作する
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,96 @@
+#はじめに
+ブラウザ自動テストのデファクトスタンダードである`Selenium`
+基本的に`Selenium`を使用して組んだプログラムは、自分自身でブラウザを起動して自動操作を開始します
+
+しかし、**起動済みのブラウザ**を自動操作したい!というケースもありますよね?
+はたして`ChromeDriver`を使って起動済みのブラウザを操作することができるのか?
+
+動かせた時の感動は省略
+
+#やったこと
+##ブラウザの起動
+今回の手法は、Google Chrome を起動するところにポイントがあります。
+コマンドライン引数で`-remote-debugging-port=9222`を指定してあげるのです!
+ [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) が有効な状態でブラウザが起動するので、 `Selenium` がアタッチできるようになるんですね。
+
+```bat
+"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" -remote-debugging-port=9222 --user-data-dir=C:\Temp_ForChrome
+```
+
+`--user-data-dir`の指定も忘れずに。
+操作対象のブラウザ以外に Google Chrome を起動している場合、
+ユーザプロファイルがあるフォルダとして同一パスをSeleniumで指定することができないようです。
+私の環境ではタイムアウトエラーになってしまいました。
+>テスト メソッド LastSelenium.検証_起動済みブラウザ操作.起動済みブラウザ操作 が例外をスローしました:
+OpenQA.Selenium.WebDriverException: The HTTP request to the remote WebDriver server for URL http://localhost:61065/session timed out after 60 seconds. ---> System.Net.WebException: 要求は中止されました: 操作はタイムアウトになりました。
+
+参考:[SeleniumでChromeのユーザープロファイルを指定しつつ同時に自分もChromeを使う方法](https://qiita.com/Hidenatsu/items/e43ba04b4b5f710784e6)
+
+##ソース
+`ChromeOptions.DebuggerAddress`にブラウザ起動時に指定したものと同じポート番号を指定します。
+ブラウザ起動済みの状態で当プログラムを実行すると、見事に動き始めます。
+
+```csharp
+var options = new ChromeOptions
+{
+ DebuggerAddress = "127.0.0.1:9222"
+};
+
+using (var driver = new ChromeDriver(options))
+{
+ var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 5));
+
+ // 任意のブラウザ操作処理 ↓↓↓
+
+ driver.Url = "https://www.google.com";
+ var q = driver.FindElementByName("q");
+ q.SendKeys("Chromium");
+ q.Submit();
+
+ wait.Until(ExpectedConditions.TitleIs("Chromium - Google 検索"));
+ ((ITakesScreenshot)driver).GetScreenshot().SaveAsFile($"{DateTime.Now.ToString("yyyyMMddHHmmss")}.png");
+
+ // 任意のブラウザ操作処理 ↑↑↑
+}
+
+```
+
+#おまけ
+Google Chrome を起動する部分がポイントだったわけです。
+ここで、手動ではなく**別プログラム経由で起動されたブラウザ**を自動操作したい場合を考えてみます。
+うまいことコマンドライン引数を渡してあげる必要がありますよね?
+
+やるとすればこんな感じか。。?
+
+```csharp
+using System.Diagnostics;
+
+/// <summary>
+/// chrome.exe という名前のアセンブリとしてビルドする
+/// </summary>
+namespace DummyChrome
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ var proc = new Process();
+ proc.StartInfo.FileName = @"C:\Program Files (x86)\Google\Chrome\Application\_chrome.exe";
+ proc.StartInfo.Arguments = @"-remote-debugging-port=9222 --user-data-dir=C:\Temp_ForChrome";
+ proc.Start();
+ }
+ }
+}
+```
+オリジナルの`chrome.exe`は`_chrome.exe`にリネームしてしまいます。
+Google Chrome の通常利用に支障が出るのはご愛敬。
+![dummyChrome.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432322/76374e92-d2d1-bd73-f7fd-ac14a91fcb60.png)
+
+#おわりに
+参考にしたページ:
+[Selenium: Attach to an existing Chrome browser with C#](https://intellitect.com/selenium-chrome-csharp/)
+
+参考になりそうでしなかったページ:
+[Re-using existing browser session in Selenium using C#](https://tarunlalwani.com/post/reusing-existing-browser-session-selenium-csharp/)
+`Reflection`をつかって`private`メンバーにアクセスしてるので黒魔術感が否めない。
+そもそもやりたいことが違う雰囲気もある。