SeleniumとMeCabを使えるJupyterLabコンテナイメージを作る

# はじめに

この2～3か月くらい、筆者は仕事でデータ収集（BeautifulSoupやSeleniumを使ったWebスクレイピング）と自然言語処理（MeCabを使った形態素解析とgensim使った単語の分散表現と感情分析）をする機会が増えてます。

過去の記事([※1](https://qiita.com/Blaster36/items/6dce4cf0b4ada88ef639)）では、WSL上でGPUの使える分析環境を整備したのですが、用途に合わせた環境がまだまだ整っておらずちょっと仕事関係のプログラミングには使えてませんでした。
Pythonライブラリはpipコマンドで（PyPI参照して）インストールも簡単なのですが、SeleniumやMeCabはpipコマンド以外のインストール作業があったりで正直大変。。。

というわけで、SeleniumとMeCabを使えるコンテナイメージをビルドして、分析環境で使えるようにしようと思い立ちました。
Webブラウザ（Google Chrome）のVerupが進むと、Selenium（ChromeDriver）との整合性が崩れて動かなくなったりもするので、環境凍結という意味でもコンテナイメージに押し固めておくと便利かもと思った次第でして。

そこで、本稿では、**「SeleniumおよびMeCabを使えるJupyterLabのコンテナイメージをビルド＆コンテナ起動するJupyterHubへの環境設定」**を順に紹介してゆく。

## 本稿で紹介すること

- JupyterHub／JupyterLabの環境設定
- Dockerコンテナイメージのビルド based on Jupyter
- JupyterHub／JupyterLabの起動
- SeleniumおよびMeCabの動作確認

[jupyterhub | Read the Docs](https://readthedocs.org/projects/jupyterhub/)
[JupyterHub &#8212; JupyterHub 1.0.0 documentation](https://jupyterhub.readthedocs.io/en/1.0.0/)
[GitHub - jupyter/docker-stacks: Ready-to-run Docker images containing Jupyter applications](https://github.com/jupyter/docker-stacks)

## 本稿で紹介しないこと

- WSL2のインストール
- Ubuntuのインストール（From Microsoft Store）　※Ubuntu 18.04.5 LTSを使用
- Dockerのインストール　※Docker Community Edition 20.10.8を使用
- Pythonライブラリ（JupyterHub、JupyterLab、Selenium、MeCab）の全般

# 環境構築
大きく、3ステップです。これら、WSL2／Ubuntu上で実行します。
1. JupyterHub／JupyterLabの環境設定
2. Dockerコンテナイメージのビルド based on Jupyter
3. JupyterHub／JupyterLabの起動

## 事前準備
過去の記事([※1](https://qiita.com/Blaster36/items/6dce4cf0b4ada88ef639)）で紹介した内容、分析環境の整備をしていること。

:::note info
以下、筆者の環境です。
:::

```
C:\>ver

Microsoft Windows [Version 10.0.22000.376]
```

```
C:\>nvidia-smi
Thu Jan  6 13:25:46 2022
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 472.08       Driver Version: 472.08       CUDA Version: 11.4     |
|-------------------------------+----------------------+----------------------+
| GPU  Name            TCC/WDDM | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ... WDDM  | 00000000:01:00.0  On |                  N/A |
| 42%   21C    P8    13W / 125W |    372MiB /  6144MiB |      2%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
```

```shell:
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.5 LTS"
```

```shell:
$ docker version
Client: Docker Engine - Community
 Version:           20.10.8
 API version:       1.41
 Go version:        go1.16.6
 Git commit:        3967b7d
 Built:             Fri Jul 30 19:54:08 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.8
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.6
  Git commit:       75249d8
  Built:            Fri Jul 30 19:52:16 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.9
  GitCommit:        e25210fe30a0a703442421b0f60afac609f950a3
 nvidia:
  Version:          1.0.1
  GitCommit:        v1.0.1-0-g4144b63
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
```

```shell:
$ sudo dpkg -l | grep -i nvidia
ii  libnvidia-container-tools      1.4.0-1                             amd64        NVIDIA container runtime library (command-line tools)
ii  libnvidia-container1:amd64     1.4.0-1                             amd64        NVIDIA container runtime library
ii  nvidia-container-runtime       3.5.0-1                             amd64        NVIDIA container runtime
ii  nvidia-container-toolkit       1.5.1-1                             amd64        NVIDIA container runtime hook
ii  nvidia-docker2                 2.6.0-1                             all          nvidia-docker CLI wrapper
```

DockerHub（[※2](https://hub.docker.com/r/jupyter/minimal-notebook)）より、JupyterLabのコンテナイメージを取得しておきます。

:::note warn
<b>Python 3.6</b>を使いたいため、本稿では<b>jupyter/minimal-notebook:9e8682c9ea54</b>を取得し、ビルド作業での元コンテナイメージとして利用してゆきます。
:::

```shell:
$ docker images
REPOSITORY                         TAG                       IMAGE ID       CREATED         SIZE
jupyterhub/jupyterhub              1.0-gpu                   79c33e7d70df   3 hours ago     420MB
postgres                           9.6                       131ab388dac1   4 months ago    200MB
nvcr.io/nvidia/pytorch             20.11-py3-gpu             dd53c8b61c4b   4 months ago    15.3GB
nvcr.io/nvidia/tensorflow          20.11-tf2-py3-gpu         f6aa8098fc48   4 months ago    12.3GB
adminer                            4.8.1                     4727f36d62d9   5 months ago    90MB
nvcr.io/nvidia/tensorflow          21.07-tf2-py3             887093b5693e   5 months ago    11.1GB
nvcr.io/nvidia/pytorch             21.07-py3                 7beec3ff8d35   5 months ago    15GB
nvcr.io/nvidia/tensorflow          20.11-tf2-py3             98a7952f7f9c   14 months ago   11.6GB
nvcr.io/nvidia/pytorch             20.11-py3                 ae35b2b3cad1   14 months ago   13.2GB
jupyterhub/jupyterhub              1.0                       c399e04fda3c   2 years ago     283MB
osixia/phpldapadmin                0.9.0                     78148b61fdb5   2 years ago     302MB
jupyter/minimal-notebook           2343e33dec46              c3bbd3471e39   3 years ago     2.72GB
jupyter/minimal-notebook           9e8682c9ea54              400c44c4a7a7   3 years ago     2.79GB
hrektts/fusiondirectory-openldap   1.1.9-1.2-1               7f2e4370509d   4 years ago     226MB
hrektts/fusiondirectory            0.2.0                     b56f1086a08d   4 years ago     345MB
```

Dockerネットワーク「jupyterhub」を作成しておきます。形態は**Bridge**です。

```shell:
$ docker network ls
NETWORK ID     NAME         DRIVER    SCOPE
d880009721fa   bridge       bridge    local
dc9d83b0f49c   host         host      local
d26548c59f23   jupyterhub   bridge    local
18e4f9062739   none         null      local
```

## 1. JupyterHub／JupyterLabの環境設定

以下、過去の記事([※1](https://qiita.com/Blaster36/items/6dce4cf0b4ada88ef639)）からの変更点です。

- SeleniumおよびMeCabを使えるJupyterLabのコンテナイメージを選択肢に登録　（該当は、先頭に*を打った2行）

以下、環境設定ファイル（jupyterhub_config.py）です。

```python:jupyterhub_config.py
c.JupyterHub.authenticator_class = 'ldapauthenticator.LDAPAuthenticator'
c.LDAPAuthenticator.valid_username_regex = r'^[a-z0-9][.a-z0-9_-]*$'
c.LDAPAuthenticator.use_ssl = False
c.LDAPAuthenticator.server_address = '${WSL2／Ubuntuのeth0}'
c.LDAPAuthenticator.server_port = 389
c.LDAPAuthenticator.bind_dn_template = 'uid={username},ou=people,ou=jhub,dc=hoge,dc=com'
c.LDAPAuthenticator.lookup_dn = False

c.JupyterHub.hub_connect_ip = 'jupyterhub'
c.JupyterHub.hub_ip = '0.0.0.0'
c.Authenticator.admin_users = {'admin', 'jupyter'}

from dockerspawner import DockerSpawner

class DemoFormSpawner(DockerSpawner):
  def _options_form_default(self):
    default_stack = 'jupyter/minimal-notebook'
    return """
    <label for="stack">Select your desired stack</label>
    <select name="stack" size="1">
*     <option value="jupyter/minimal-notebook:9e8682c9ea54-MeCab">jupyter/minimal-notebook(w/MeCab)</option>
*     <option value="jupyter/minimal-notebook:9e8682c9ea54-MeCab-Slum">jupyter/minimal-notebook(w/MeCab/Selenium)</option>
      <option value="nvcr.io/nvidia/tensorflow:20.11-tf2-py3-custom">nvcr.io/nvidia/tensorflow</option>
      <option value="nvcr.io/nvidia/pytorch:20.11-py3-custom">nvcr.io/nvidia/pytorch</option>
    </select>
    """.format(stack=default_stack)

  def options_from_form(self, formdata):
    options = {}
    options['stack'] = formdata['stack']
    container_image = ''.join(formdata['stack'])
    print('SPAWN: ' + container_image + 'IMAGE')
    self.image = container_image
    return options

c.JupyterHub.spawner_class = DemoFormSpawner

notebook_dir = '/home/jovyan'
c.DemoFormSpawner.notebook_dir = notebook_dir
c.DemoFormSpawner.volumes = {'jupyterhub-user-{username}':notebook_dir}
c.DemoFormSpawner.remove = True
c.DemoFormSpawner.default_url = '/lab'
c.DemoFormSpawner.start_timeout = 300
c.DemoFormSpawner.http_timeout = 120
c.DemoFormSpawner.network_name = 'jupyterhub'
```

## 2. Dockerコンテナイメージのビルド based on Jupyter

コンテナイメージは2つビルドしますが、元コンテナイメージは共通です。
[jupyter/minimal-notebook](https://hub.docker.com/r/jupyter/minimal-notebook)

### その①：MeCab版

以下、コンテナイメージのビルド用環境設定ファイル（MeCab版）です。
必要なソフトウェア（含むPythonライブラリ）は全てインターネットで取得しています。

```shell:Dockerfile.mecab.lab
FROM jupyter/minimal-notebook:9e8682c9ea54

USER jovyan
RUN python3 -m pip install pip==21.2.2
RUN python3 -m pip install notebook==6.0.2
RUN python3 -m pip install nbformat==5.1.3
RUN python3 -m pip install nbconvert==5.6.0
RUN python3 -m pip install nbclient==0.5.3
RUN python3 -m pip install tornado==6.0.3
RUN python3 -m pip install jupyter_client==6.1.12
RUN python3 -m pip install jupyter-core==4.6.1
RUN python3 -m pip install jupyterhub==1.0.0
RUN python3 -m pip install jupyterlab==1.2.3
RUN python3 -m pip install jupyterlab-server==1.0.6
RUN python3 -m pip install ldap3==2.7
RUN python3 -m pip install mecab-python3==1.0.1

USER root
RUN cat /etc/lsb-release
RUN apt-get update
RUN apt-get install -y iputils-ping net-tools
RUN apt-get install -y mecab libmecab-dev
RUN apt-get install -y mecab-ipadic mecab-ipadic-utf8
RUN apt-get install -y libc6-dev build-essential
```

以下、ビルドコマンドです。

```shell:
$ docker build -t jupyter/minimal-notebook:9e8682c9ea54-MeCab -f Dockerfile.mecab.lab .
```

### その②：MeCab＋Selenium版

以下、コンテナイメージのビルド用環境設定ファイル（MeCab+Selenium版）です。
必要なソフトウェア（含むPythonライブラリ）は一部インターネットで取得しています。

:::note warn
SeleniumはPythonライブラリのためpipコマンドでPyPIからインストールも可能ですが、Google ChromeおよびChromeDriverと合わせて予めダウンロードしてインストールする方法としています。
:::

Google ChromeおよびChromeDriverについては、Ver.90.0.4430.*で揃えています。
[Download older versions of Google Chrome for Windows, Linux and Mac](https://www.slimjet.com/chrome/google-chrome-old-version.php)
[ChromeDriver - WebDriver for Chrome - Downloads](https://chromedriver.chromium.org/downloads)

```shell:Dockerfile.selenium.lab
FROM jupyter/minimal-notebook:9e8682c9ea54

COPY ./google-chrome-stable_current_amd64.deb /home/jovyan/
COPY ./selenium-3.141.0.tar.gz /home/jovyan/
COPY ./chromedriver_linux64.zip /home/jovyan/

USER jovyan
RUN python3 -m pip install pip==21.2.2
RUN python3 -m pip install notebook==6.0.2
RUN python3 -m pip install nbformat==5.1.3
RUN python3 -m pip install nbconvert==5.6.0
RUN python3 -m pip install nbclient==0.5.3
RUN python3 -m pip install tornado==6.0.3
RUN python3 -m pip install jupyter_client==6.1.12
RUN python3 -m pip install jupyter-core==4.6.1
RUN python3 -m pip install jupyterhub==1.0.0
RUN python3 -m pip install jupyterlab==1.2.3
RUN python3 -m pip install jupyterlab-server==1.0.6
RUN python3 -m pip install ldap3==2.7
RUN python3 -m pip install mecab-python3==1.0.1
RUN python3 -m pip install /home/jovyan/selenium-3.141.0.tar.gz

USER root
RUN cat /etc/lsb-release
RUN apt-get update
RUN apt-get install -y iputils-ping net-tools
RUN apt-get install -y mecab libmecab-dev
RUN apt-get install -y mecab-ipadic mecab-ipadic-utf8
RUN apt-get install -y libc6-dev build-essential
RUN dpkg -i /home/jovyan/google-chrome-stable_current_amd64.deb
RUN unzip /home/jovyan/chromedriver_linux64.zip
RUN mv /home/jovyan/chromedriver /usr/local/bin/
RUN chown root:root /usr/local/bin/chromedriver

RUN rm -rf /home/jovyan/google-chrome-stable_current_amd64.deb
RUN rm -rf /home/jovyan/selenium-3.141.0.tar.gz
RUN rm -rf /home/jovyan/chromedriver_linux64.zip
```

以下、ビルドコマンドです。

```shell:
$ docker build -t jupyter/minimal-notebook:9e8682c9ea54-MeCab-Slum -f Dockerfile.selenium.lab .
```

## 3. JupyterHub／JupyterLabの起動

以下、環境設定（環境変数の定義）を含む起動コマンドです。
過去の記事([※1](https://qiita.com/Blaster36/items/6dce4cf0b4ada88ef639)）からの変更なしです。

```shell:
$ docker run -v /var/run/docker.sock:/var/run/docker.sock -p 8000:8000 -p 8001:8001 -p 8081:8081 \
  -d --name jupyterhub --net jupyterhub jupyterhub/jupyterhub:1.0-gpu
```

Webブラウザで http://127.0.0.1:8000/hub/login にアクセスし、JupyterHubのログイン画面が表示できればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685193/1d4b53ce-e764-4cb4-19ba-71a1d075ae7b.png)

そして、ログインすると、（起動対象の）コンテナイメージ選択画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685193/8440adf0-1d8a-03f5-4f2c-e2ab26141eff.png)

用途を鑑みてコンテナイメージを選択し、JupyterLabコンテナを起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685193/59b1fe0d-70cd-3a18-4279-c022a8f5a45c.png)


# では早速、動作確認

## MeCab編

形態素解析を実行します。
以下、確認用のCode例です。分かち書きの形式で出力しています。

:::note info
ポイントは、Taggerのインスタンス化オプションです。筆者環境だと、システム辞書を指定しただけだとエラーになるため、リソースファイルを指定しています（-r /etc/mecabrcでもOK）。
:::

```python:
import MeCab
wakati = MeCab.Tagger("-d /var/lib/mecab/dic/debian -r /dev/null -Owakati")
sentence_wakati = wakati.parse("私は猫が好きです").split()
print(sentence_wakati)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685193/81dd8f01-3005-3183-fa96-cb26437e959e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685193/3f8cfbc6-5d56-6348-d7ea-2b8acb2b6ec7.png)

## Selenium編

Webスクレイピング（元ネタは**[コチラ](https://pystyle.info/scraping-tutorials-for-website-using-javascript/)**）を実行します。
以下、確認用のCode例です。Yahoo! ニュースTopの見出しとリンク先URLを出力しています。

:::note info
ポイントは、Google Chromeの起動オプションです。ヘッドレスはMUSTで、いくつか元ネタに対し追加しています。
:::

```python:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

op = Options()
op.add_argument('--headless')
op.add_argument('--no-sandbox')
op.add_argument('--disable-dev-shm-usage')
op.add_argument('--disable-dev-gpu')
op.add_argument('--disable-dev-extensions')
op.add_argument('--ignore-certificate-errors')
op.add_argument('--ignore-ssl-errors')

driver = webdriver.Chrome(options=op)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685193/ddfc318f-d889-e40a-1964-efdd8f1874e4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685193/68f63cc6-70b6-9867-6be6-115788b63257.png)

# まとめ

とりあえずは、SeleniumとMeCabを使えるJupyterLabコンテナイメージを作ることができました。問題なく、使えています。
データ分析でよく使うPythonライブラリ群を内包したコンテナイメージ（[jupyter/scipy-notebook
](https://hub.docker.com/r/jupyter/scipy-notebook)）を使うのも一手かな。あと、Pythonのバージョンも新しくするとか。