Selenium Serverの使い方メモ

# Selenium Serverとは


Selenium Serverはリモート環境でSelenium WebDriverを動かすためのサーバーです


公式からdockerイメージが提供されていてChrome, Chromium, Edge, Firefoxなどのブラウザ環境が容易に準備可能ですので、マルチブラウザ対応テストがポータブルに実行可能です。また、多数のコンテナをselenium/hubコンテナでまとめて制御することが出来るので並列テストも実行することができます


# 1. 単独で使う


## 1-1. dockerイメージの選択


以下に一覧があるのでここから選びます
https://hub.docker.com/u/selenium


standaloneとあるのが単独で利用するタイプのdockerイメージで、Chrome, Chromium, Edge, Firefoxが選択できます


## 1-2. docker runから実行


Selenium Serverはデフォルトで4444番ポートで待機しますのでdocker起動時にポートを繋げてやります。また、dockerはデフォルトで/dev/simの容量が64MBしかない為、Selenium Serverが動作している間にこれを超えて動作停止してしまうのを防ぐために多めの2GBを指定して実行します


```docker:Chromeの場合
docker run -d -p 4444:4444 --shm-size="2g" selenium/standalone-chrome
```


これでlocalhsot:4444に待機している筈なのでPython+selenium環境であれば以下のようにすれば使う事が出来ます。driverを定義して以降の使い方はまったく同じなので、以前ローカル環境で動かしていたseleniumのコードがあればそのまま使う事ができます


```python:python
from selenium import webdriver

jupyter_url = 'http://selenium_server:4444/wd/hub'

options = webdriver.ChromeOptions()  # ブラウザごとにここを変更する
driver = webdriver.Remote(
    command_executor=jupyter_url,
    options=options
)

driver.get("https://www.google.com")
print(driver.title)

driver.quit()
```


ブラウザによってoptions引数に渡す内容が変わります


```python: Chrome, Chromiumの場合
options = webdriver.ChromeOptions()
```


```python: Firefoxの場合
options = webdriver.FirefoxOptions()
```


```python: Edgeの場合
options = webdriver.EdgeOptions()
```


OperaはW3Cから外れたのでselenium側からの対応はなくなったようです


## 1-3. リモートブラウザでGUIデバッグを実行する


Selenium ServerはVNCによるアクセスに対応しているので、ブラウザをGUI表示しながらデバッグしたりというのが可能です。VNCの5900番ポートを使うのでこれも空けてやります


```docker:terminal
docker run -d -p 4444:4444 -p 5900:5900 --shm-size="2g" selenium/standalone-chrome
```


適当なVNCクライアントを使って127.0.0.1:5900にアクセスすれば利用できます
ログイン時のデフォルトパスワードは「secret」です


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/d8ba5309-9b84-9aba-700b-dad6eed8daaa.png" width=50%>


### パスワードの変更


パスワードを変更したい場合は環境変数として与えると反映してくれます


```docker:terminal
docker run -d -p 4444:4444 -p 5900:5900 --shm-size="2g" -e VNC_PASSWORD=yourpassword selenium/standalone-chrome
```


ちなみに、9222番ポートを開けてやればリモートDevToolsも使えるようです
すごい


## 1-4. docker compose upから実行


docker compose upから使用したい場合は以下のように書けます
RDPの7900も空けてるのは


```yml:docker-compose.yml
services: 
  selenium_server:
    image: selenium/standalone-chrome:latest
    container_name: selenium_chrome
    ports:
      - "4444:4444"
      - "5900:5900"
    shm_size: "2g"
    restart: unless-stopped
```


# 2. Selenium Gridを使う


hubサーバーを使って、複数起動したnodeサーバーを動かすことが出来ます
多数のコンテナから一気にアクセスして並列テストをやったりというのができます


## 2-1. dockerイメージを選ぶ


hubサーバーのイメージが以下
https://hub.docker.com/r/selenium/hub


イメージ名にnodeと書かれているのがnodeサーバーです
Chrome, Edge, Firefox, Operaが選択できます
https://hub.docker.com/u/selenium


## 2-2. 使い方


今回はやりませんでしたが、以下に手順説明があります
https://www.selenium.dev/documentation/grid/getting_started/#hub-and-node


# 3. ARM CPUで使用する場合


ラズパイなどのARMアーキテクチャのCPU環境では、Chromeのコンテナが対応していないようです
Chromium, Firefox, Edgeは使用できますのでこれらを選択することになりそうです


# 4. その他運用上の注意点


## 4-1. セッション管理


Selenium Serverが同時実行できるセッションは１つだけです
(増やすときはGridを使う想定のようです)


ローカル環境でやってると実行プロセスがそのままseleniumのプロセスなので、実行が終わる度にseleniumも終了しますからセッションを意識する必要はありませんが、Selenium Serverはサーバーが立ちっぱなしなのでセッション終了を明示的にやらないといけません。接続中のセッションが終了しないまま接続も続いているとタイムアウトもしなくなってしまいますので、次のセッションを始めることができなくなります
(SessionNotCreatedException() が出ます)


処理の例外発生時などにやりがちだと思いますので、例外処理を書いてdriver.quit()してから終了するように書きましょう


```python
driver.quit()
```


## 4-2. タイムアウト


Selenium Serverのタイムアウトには以下のようなものがあります


| タイムアウト種類         | デフォルト時間      | 適用対象             | 目的                                  |
|----------------------|--------------|-----------------|----------------------------------|
| セッションタイムアウト  | 300秒  | WebDriver セッション | 一定時間操作がない場合にセッションを終了 |
| ページロードタイムアウト | 300秒  | ページの読み込み       | ページが長時間ロードし続けるのを防ぐ   |
| スクリプトタイムアウト  | 30秒         | JavaScript 実行   | JavaScriptが長時間実行されるのを防ぐ |
| 暗黙的な待機時間       | 0秒          | 要素の検索          | 要素が見つかるまでの待機時間を自動設定 |


スクリプトタイムアウトは30秒と短めなので、間欠的な処理をやる場合などでスクリプトタイムアウトしてしまうことはありそうですし、逆にタイムアウトを早くして例外拾って処理したい場合もありそうです


それぞれ設定するには以下のように書けます


```python:ページロードタイムアウト
driver.set_page_load_timeout(60)  # 60秒でページロードをタイムアウト
```


```python:スクリプトタイムアウト
driver.set_script_timeout(20)  # JavaScriptの実行時間を20秒に制限
```


# まとめ


こんな便利なものがあったとは
レッツトライ