【Selenium】WSLからホストOS上のドライバを叩いてブラウザを表示したい

# はじめに
WSLはWindowsを使っていながらにしてLinuxのコマンドを使えるという点で非常に便利なのですが、ことSeleniumに関して言えば、UbuntuのGUIを利用できないためブラウザの挙動が確認しづらいという難点があります。

仮想ディスプレイを立ち上げてスクリーンショットを取ればその時点での画面表示を確認することはできます[^1]が、やはり実際に動いている様子を見るに如くは無しといったところではないでしょうか。

色々試行錯誤した結果、Selenium Gridを使用することでWSL2からホストOS上のドライバを叩いてブラウザを表示することに成功したので共有させていただきます。

# 環境
ホストOS: Windows 10 Home 20H2
WSL: Ubuntu 18.04.5 on WSL2
Python: 3.7.5

# 先行研究
[WSL (Ubuntu16.04.4 LTS) 上の Python から、Selenium を利用して Windows側のウェブブラウザを操作する – ラボラジアン](https://laboradian.com/operate-browser-on-win-by-python-of-wsl-via-selenium/)
⇒2年以上前の記事ということもあり、自分の環境では再現できませんでした。
　`Can not connect to the Service`というエラーメッセージが出ます。環境を揃えれば可能かも。

[WSL2 上で起動した Selenium Webdriver や Puppeteer から Windows 側の Chrome ウィンドウを操作したかったが無理 - Corredor](https://neos21.hatenablog.com/entry/2020/10/13/080000)
⇒解決には至っていませんが、先行研究に対するリファレンスが豊富なのでPython以外の言語で開発している人は参考になるかもしれません。

# 方法１：Selenium3（信頼度：中）
### ①Windows: Java（11以上）をインストールする。
手順は以下を参照してください。Java10以下だとエラーになる可能性があります。
[OpenJDK11のインストール方法メモ - Qiita](https://qiita.com/shibafu/items/8762636f66d7fef49d59)

### ②Windows: Selenium Server (Grid)をダウンロードする。
[こちら](https://www.selenium.dev/downloads/)のページへアクセスして、`3.141.59`をダウンロードします。
ダウンロードしたファイルの配置先は特に決まっていません。

### ③Windows: ブラウザのドライバをダウンロードする。
ChromeDriverは[こちら](https://chromedriver.chromium.org/downloads)、geckodriver(Firefox)は[こちら](https://github.com/mozilla/geckodriver/releases)から。
**Windowsにインストールされているブラウザと同じバージョン**のドライバをダウンロードしてください。
ダウンロードしたzip等のファイルを展開し、実行ファイル（chromedriver.exeやgeckodriver.exe）を**②でダウンロードしたjarファイルと同じフォルダ**に配置します。

### ④Windows: Selenium Serverを起動する。
Selenium Grid 3ではHubとNodeという2つのプロセスを立てる必要があるので、コマンドプロンプトを2つ立ち上げます。
まず、片方のコマンドプロンプトで以下のコマンドを実行してHubを起動します。

```
java -jar [jarファイルの格納場所]\selenium-server-standalone-3.141.59.jar -role hub
```
以下のような出力がなされ、プロセスが終了しなければ問題ありません。

```
13:11:40.423 INFO [GridLauncherV3.parse] - Selenium server version: 3.141.59, revision: e82be7d358
13:11:40.483 INFO [GridLauncherV3.lambda$buildLaunchers$5] - Launching Selenium Grid hub on port 4444
2020-11-23 13:11:40.848:INFO::main: Logging initialized @636ms to org.seleniumhq.jetty9.util.log.StdErrLog
13:11:41.814 INFO [Hub.start] - Selenium Grid hub is up and running
13:11:41.816 INFO [Hub.start] - Nodes should register to http://192.168.21.1:4444/grid/register/
13:11:41.816 INFO [Hub.start] - Clients should connect to http://192.168.21.1:4444/wd/hub
```
次にもう一方のコマンドプロンプトで以下のコマンドを実行してNodeを起動します。`[HubのURL]`には、上の出力で`Clients should connect to`のあとに続くURLを代入します。

```
java -jar [jarファイルの格納場所]\selenium-server-standalone-3.141.59.jar -role node -hub [HubのURL]:4444
```
以下のような出力がなされ、プロセスが終了しなければ問題ありません。

```
13:11:59.609 INFO [GridLauncherV3.parse] - Selenium server version: 3.141.59, revision: e82be7d358
13:11:59.688 INFO [GridLauncherV3.lambda$buildLaunchers$7] - Launching a Selenium Grid node on port 31688
2020-11-23 13:12:00.999:INFO::main: Logging initialized @1598ms to org.seleniumhq.jetty9.util.log.StdErrLog
13:12:01.177 INFO [WebDriverServlet.<init>] - Initialising WebDriverServlet
13:12:01.231 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 31688
13:12:01.231 INFO [GridLauncherV3.lambda$buildLaunchers$7] - Selenium Grid node is up and ready to register to the hub
13:12:01.654 INFO [SelfRegisteringRemote$1.run] - Starting auto registration thread. Will try to register every 5000 ms.
13:12:01.883 INFO [SelfRegisteringRemote.registerToHub] - Registering the node to the hub: http://192.168.21.1:4444/grid/register
13:12:02.317 INFO [SelfRegisteringRemote.registerToHub] - The node is registered to the hub and ready to use
```
### ⑤WSL: Selenium3.141.0をインストールする。

```
pip install selenium==3.141.0
```

### ⑥WSL: サンプルコードを作成する。

```Python:sample.py
from selenium import webdriver

chrome_options = webdriver.ChromeOptions()
driver = webdriver.Remote(
    command_executor="http://192.168.21.1:4444/wd/hub",
    options=chrome_options
    )
driver.get("https://www.google.com/search?q=qiita")
```
`command_executor`には先程の`Clients should connect to`のあとに続くURLを指定します。
`ChromeOptions()`を`FirefoxOptions()`とするとgeckodriverを使用することになります。

### ⑦WSL: サンプルコードを実行する。
```
python sample.py
```
成功すると以下のようになります。
![selenium_demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507842/06516cad-e29f-fe28-e83c-fb9b839cedcf.gif)

# 方法２：Selenium4（信頼度：高）
実を言いますと、上のSelenium3での方法は元々上手くいっておらず、Seleniumのソースをいじって成功させる抜け道は見つけていたのですがそれを紹介するのもどうかと思って一度お蔵入りにしていたんです。
その後Selenium4での実装方法を発見し、この記事を書くに際して改めてSelenium3で検証したら上手くいったという経緯があります。
「じゃあ確実性の高い方を先に紹介しろよ」というご意見も尤もなのですが、Selenium4はまだプレリリースですので、安定版のSelenium3で上手くいくならそれに越したことはないと思ってそちらを優先した次第です。長々と前置き失礼しました。

### ①Windows: Java（11以上）をインストールする。
Selenium3と同様のため省略。Java11以上でないと確実にエラーになります。

### ②Windows: Selenium Server (Grid) 4をダウンロードする。
[こちら](https://www.selenium.dev/downloads/)のページへアクセスして、`Latest Selenium 4 Alpha version`と書かれているリンクからダウンロードをします。

### ③Windows: ブラウザのドライバをダウンロードする。
Selenium3と同様。違いとしては、実行ファイルの配置場所をjarファイルと同じにする必要はありません。

### ④Windows: ドライバのパスをシステム環境変数PATHに追加する。
Selenium4のみで必要な手順です。
［スタート］→［設定］で設定画面を開き、検索ボックスに「環境変数」と入力すると「環境変数を編集」と「システム環境変数の編集」という２つの候補が出てくるので、「システム環境変数の編集」の方を選択します。
![スクリーンショット 2020-11-23 165701.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507842/15a08afb-c4bb-65da-4285-8e96d71963b3.png)

すると以下のような画面が開くので、「環境変数」を押下します。
![スクリーンショット 2020-11-23 165510.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507842/7f354950-fef0-f71d-ebf1-7e63f23a9e23.png)
「環境変数」画面が開いたら、「システム環境変数」テーブルの`Path`行を選択し、「編集」を押下します。
![スクリーンショット 2020-11-23 165853.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507842/c169defa-43c8-3ec5-7028-1046d6d8ed72.png)
「環境変数名の編集」画面が開いたら「新規」を押下し、ブラウザのドライバが格納されているフォルダのパスを入力します。入力が完了したらEnterキーで確定し、「OK」を押下します。
![スクリーンショット 2020-11-23 170220.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507842/0d6f24e1-2d53-bfca-53c1-d67b6d3016f4.png)
「環境変数」画面と「システムのプロパティ」画面で「OK」を押下し、「設定」画面を閉じて完了です。

### ⑤Windows: Selenium Serverを起動する。
Selenium Grid 4には`standalone`というモードがあり、これを使えば一つのコマンドプロンプトで全てのコンポーネントを起動できます。

コマンドプロンプトを起動し、以下のコマンドを実行します。ファイル名はダウンロードしたバージョンによって異なるのでご注意ください。

```
java -jar [jarファイルの格納場所]\selenium-server-4.0.0-alpha-7.jar standalone
```
コマンド出力の最終行が以下のようになり、プロセスが終了しなければ問題ありません。

```
17:08:44.674 INFO [Standalone.execute] - Started Selenium standalone 4.0.0-alpha-7 (revision Unknown): http://172.26.240.1:4444
```

### ⑥WSL: Selenium4をインストールする。

```
pip install selenium==4.0.0a7
```
Seleniumをインストール済みの場合、以下のコマンドでアップグレード可能です。

```
pip install -U --pre selenium
```
Pythonのバージョンが3.8以上だとSelenium==4.0.0a7のインストールに失敗するようなので、その場合はPythonのバージョンを下げるかSelenium==4.0.0a6をインストールするかのどちらかになると思います。**Seleniumのバージョンを下げる場合、Selenium Serverのバージョンも合わせて下げる必要がある**のでご注意ください。

### ⑦WSL: サンプルコードを作成する。
Selenium3と同様。`command_executor`に設定するURLがSelenium3と4で異なる可能性があるので、必要に応じて変更してください。

### ⑧WSL: サンプルコードを実行する。
```
python sample.py
```
成功すると以下のようになります。

![selenium4_demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507842/96ccbb10-bc9a-bb96-4f89-5abb3af81917.gif)

# あとがき
Javaに全く詳しくないので、jarファイルを実行してエラーが出たときはわからなさすぎて泣きそうになりましたが、結果的に上手くいって安心しました。**Javaのバージョン**と**システム環境変数PATH**がポイントだったかなと思います。お役に立てれば幸いです。

最後までご覧頂きありがとうございました。

# 参考文献
[Remote WebDriver client :: Documentation for Selenium](https://www.selenium.dev/documentation/en/remote_webdriver/remote_webdriver_client/)
[Grid :: Documentation for Selenium](https://www.selenium.dev/documentation/en/grid/)

[^1]: このやり方については以下のページが参考になりました。[Python: Selenium + Headless Chrome で Web ページ全体のスクリーンショットを撮る - CUBE SUGAR CONTAINER](https://blog.amedama.jp/entry/2018/07/28/003342)