Python: Selenium: Dockerで、Chromeブラウザ最新版が動く仮想環境を立てて、24時間自動WEBサーフィンさせる環境の基礎を作る

Selenium は、プログラムコードでWEBブラウザを自動操縦できるソフトウェアです。
ただSeleniumを使ってWEBブラウザを自動操縦するにしても、そのままでは、実行するのにPCやMacが必要です。あなたが寝てる間もPCやMacを起動しっぱなしにするのは不毛ですよね。

そこで有用なのが docker-selenium です。

https://github.com/SeleniumHQ/docker-selenium

ブラウザが動く仮想環境をDockerで好きなように立てられる便利なOSSです。
docker-selenium を使えば、AWSなどクラウド環境を利用して24時間自動WEB巡回や自動テストを実行させる環境を構築できます。

ところで、WEBブラウザは色々ありますよね。
その中でもメジャーなのはやはりGoogle Chrome。
Chromeを使いたい。

ただそのままでは、最新版Chromeが動くDockerイメージ `selenium/node-chrome`（v4.x。Chromeバージョンは100.X）で起動したdockerコンテナにリモート接続してChromeを自動操縦することができませんでした。chromedriverでエラーが発生します。（Firefoxなら動いたのですが・・・。）
今回はそれを解決しました。

何はともあれまず動作確認して頂くために、ご用意した一式を実行してみてください。

# 注意書き

M1 Mac + Docker Desktop for Mac では動きません。
詳細は[こちら](#他にハマったこと)

# 手順

## こちらのGitHubリポジトリをcloneしてください

https://github.com/yagrush/docker-selenium-server-sample

```bash
git clone https://github.com/yagrush/docker-selenium-server-sample.git
```

## Selenium Grid（Seleniumサーバ群一式）を起動します

```bash
cd docker-selenium-server-sample
docker-compose up --build
```

「Selenium Gridって何ぞや？」とご興味があれば、公式サイトを見て観てください。

https://www.selenium.dev/ja/documentation/grid/


## テスト実行用コンテナから、テストプログラムを実行してみます

まず、テスト実行用コンテナのbashプロンプトに入ります。

```bash
docker exec -it seleniumhub-test bash
```

テスト実行用コンテナから、Selenium Gridにテスト実行をリクエストするプログラムを起動します。

```bash
pwd
/src
# 現在地が /src でなかったら、 cd /src してください

python test-chrome-from-container.py

/src/test-chrome-from-container.py:16: DeprecationWarning: desired_capabilities has been deprecated, please pass in an Options object with options kwarg
  driver = webdriver.Remote(

```

テストプログラムは、以下を実行するようになっています。

1. Google検索にジャンプして、
1. `ちいかわ うさぎ` と検索して、
1. １ページ目の検索結果の中からランダムに１つ選んでジャンプします。

プロンプトに何かを返すようにはなっていないので、すんなり実行完了しますが焦らないでください。

## Dockerコンテナを停止する

テストプログラムが完了したら、いったん `Ctrl-C` で `docker-compose up --build` を停止させます。（この後記載している、seleniumhub-chromeコンテナ内でChromeブラウザを自動操縦している様子を動画撮影しているのを完了させるためです）

## seleniumhub-chromeコンテナ内でChromeブラウザを起動して自動操縦した様子を動画で確認する

`docker-selenium-server-sample/videos/seleniumhub-chrome.mp4` が出力されていると思います。この動画ファイルを開いてみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553715/ce74c0af-2812-0764-22ba-ce50b84bf98e.png)

動画で、seleniumhub-chromeコンテナ内のデスクトップ上でChromeが自動操縦されている様子を確認できたでしょうか？
これで、ちゃんと動いているということになります。

（ちなみに動画撮影機能は、https://github.com/SeleniumHQ/docker-selenium プロジェクトによる `selenium/video` Dockerイメージによって提供されているのを使用しています。詳しくは `docker-compose.yml` の中身を確認してみてください。）

# chromedriverのエラーを解決するためにしたこと

冒頭に書いた通り、Dockerイメージ `selenium/node-chrome` v4.x をただ使用しただけでは、エラーが発生して動作しません。

chromedriverの公式サイトを調べていて「root権限でないと動かないことがある。`--no-sandbox`オプションを指定する必要があるけど（セキュリティ的にあまりオススメできないよ）」という記載があったので、https://github.com/SeleniumHQ/docker-selenium をcloneして、Dockerビルド定義の一部をカスタマイズしたものを作りました。

## selenium-chrome.Dockerfile
```Dockerfile
.
.
.
#=================================
# Chrome Launch Script Wrapper
#=================================
COPY wrap_chrome_binary /opt/bin/wrap_chrome_binary
RUN /opt/bin/wrap_chrome_binary

# ★コメントアウト
# USER 1200 <- ここ

#============================================
# Chrome webdriver
#============================================
# can specify versions by CHROME_DRIVER_VERSION
# Latest released version will be used by default
.
.
.
```

chromeのセットアップはrootで行われていましたが、chromedriverのセットアップは一般ユーザーで行われていたので、rootで行うよう改変したところ無事動くようになりました。

# 他にハマったこと

M1 Macでは結局動きませんでした。
なかなか気づかず、大分時間を浪費してしまいました。

Chromeのarm64（M1 CPUネイティブ）版がないので、Docker Desktop for Macで起動したDockerコンテナ内でChrome amd64版（しか選択肢がない）を使う限りは、どうやってもクラッシュします。
コアな部分で、M1 CPUでエミュレートしきれていない処理があるようです。

ChromeではなくChromiumならarm64版があるようなので、それなら動きそうです。

あるいは、AWSなどクラウド上のLinuxでDockerコンテナを起動すれば良いかもですね。