【Selenium】急にModuleNotFoundError: No module named 'packaging'が起きた

# 結論
`webdriver-manager==3.8.4`で、内部で使っている`packaging`モジュールが自動でインストールするように設定されてない**開発側のバグ**

# 経緯
あるサイトをスクレイピングするために、新しく環境を構築してから実行したらいつも通りに行かなかった。

```zsh:Terminal
pip install selenium webdriver-manager
```

## 環境

| System | Version |
| :-: | :-: |
| OS | MacOS Monterey(12.1) |
| zsh | zsh 5.8 (x86_64-apple-darwin21.0) |
| Python | Python 3.9.13 |
| pip | pip 22.2.2 |

# 該当のソースコード

```python:scraping.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
from time import sleep

b = webdriver.Chrome(ChromeDriverManager().install())

...
...
```

# エラー文
```python:Traceback
Traceback (most recent call last):
  File "/Users/syoshika/../scraping.py", line 3, in <module>
    from webdriver_manager.chrome import ChromeDriverManager
  File "/Users/sho/opt/anaconda3/envs/../webdriver_manager/chrome.py", line 7, in <module>
    from webdriver_manager.drivers.chrome import ChromeDriver
  File "/Users/sho/opt/anaconda3/envs/../webdriver_manager/drivers/chrome.py", line 1, in <module>
    from packaging import version
ModuleNotFoundError: No module named 'packaging'
```

# 考えたこと

そもそも`webdriver_manager`パッケージの`chrome.py`の中で起きちゃってることだから俺のせいじゃないって思いながらも、**モジュールがない**んだから`pip`でインストールすればいいのかな。

いれたら普通に動いた。でも`packaging`モジュールはいつもいらなかったはず

# 原因

`weddriver_manager`の`3.8.4`から、
**内部処理で`packaging`モジュールを必要とする**ようになって、それが`webdriver_manager`を入れたときに自動的にインストールする設定になってなかった。

この問題はすでにissueにも上がってた。

https://github.com/SergeyPirogov/webdriver_manager/issues/460

> As temporary fix you could manually install 'packaging' until the new version is released.


```shell:Terminal
 pip list | grep webdriver_manager

>> webdriver-manager  3.8.4
```

ちゃんと`3.8.4`をインストールしてしまっている

# 対策

### 1. `pip install packaging`する
と言うわけで、アプデされるまで自分で`packaging`をインストール

```zsh:Terminal
pip install packaging
```

無事に動く。

---
### 前のバージョンに戻す

`3.4.3`に戻してる人がいたのでそれでやってみる

```python
pip install webdriver-manager==3.4.3
```
これも動く。

# 終わりに

いつも`pip install`でバージョン指定せずにインストールするばかりに、最新のバグに遭遇することが多いから、1つ前の安定したものをインストールするようにしようかな。


issueで話していることについて、自分もpackageを開発したことがあるから内容がスッと入ってきた。
（コロコロナちゃん）

https://pypi.org/project/corocorona/


すぐに修正が入ると思うけど、びっくりしたので記事に残しておく。

# 原因の原因
ユーザーがあるパッケージをインストールしたときに、そのパッケージで使われている**依存したパッケージ**を自動的にインストールさせるには`setup.py`にその記述が必要になる。

実際に`webdriver-manager`のソースコードを見てみると、
```python:setup.py
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
...
...
        'Operating System :: Unix',
        'Operating System :: MacOS',
    ],
    install_requires=[
        'requests',
        'python-dotenv',
        'tqdm'
    ],
)
```
`install_requires`に、依存している`packaging`が入ってないのがわかる。
つまり、**自動でインストールするよう認識していない**

Githubに上がっているものはすでに修正されてた。

https://github.com/SergeyPirogov/webdriver_manager/blob/master/setup.py

はよpypiに載せてや。


# 原因の原因の原因
気になったので、この`packaging`が何に使われているか調べてみた。

https://github.com/SergeyPirogov/webdriver_manager/blob/master/webdriver_manager/drivers/chrome.py

> `from packaging import version`

必要なのは`version`ってやつで、こいつがバージョンのパースをしてくれるみたいなので比較とかで使えるっぽい。

```python:webdriver_manager/webdriver_manager/drivers/chrome.py
 if version.parse(browser_version) < version.parse("106.0.5249.61") :
```

比較して何になるんだって思ったけど、そのすぐ上にコメントアウトで理由が書いてあった。

> For Mac ARM CPUs after version 106.0.5249.61 the format of OS type changed to more unified "mac_arm64".
For newer versions, it'll be "mac_arm64" by default, for lower versions we replace "mac_arm64" to old format - "mac64_m1".

`chromedriver`の`version 106.0.5249.61`以降より、OSのフォーマットタイプ（os_type）なるものが変わったらしくて、

```python:webdriver_manager/webdriver_manager/drivers/chrome.py
 if version.parse(browser_version) < version.parse("106.0.5249.61") :
    os_type = os_type.replace("mac_arm64", "mac64_m1")
```
のように変更する必要があるみたい。

この`os_type`が何なのかというと、`chromedriver`のダウンロード画面に行けばわかる。

https://chromedriver.chromium.org/downloads

![スクリーンショット 2022-11-12 15.28.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777324/4a53d1e4-ed0e-68a2-efe3-c3fb8f3b91a6.png)

![スクリーンショット 2022-11-12 15.29.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777324/c40c83ad-5695-019d-8ee8-5c88209a5f0c.png)

確かに、
`chromedriver_mac64_m1.zip`から
`chromedriver_mac_arm64.zip`に変更されている。

こんな些細な変更が、
`get_url()`関数で正しいurlを返すことができず、結果**ChromeDriverがインスタンスを生成できない**ってことになるんだね。

```python:
def get_url(self):
    ...
    ...
    return f"{self._url}/{browser_version}/{self.get_name()}_{os_type}.zip"
```

以上、自分がスッキリしただけ。