結論
webdriver-manager==3.8.4で、内部で使っているpackagingモジュールが自動でインストールするように設定されてない開発側のバグ
経緯
あるサイトをスクレイピングするために、新しく環境を構築してから実行したらいつも通りに行かなかった。
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 |
該当のソースコード
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())
...
...
エラー文
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にも上がってた。
As temporary fix you could manually install 'packaging' until the new version is released.
pip list | grep webdriver_manager
>> webdriver-manager 3.8.4
ちゃんと3.8.4をインストールしてしまっている
対策
1. pip install packagingする
と言うわけで、アプデされるまで自分でpackagingをインストール
pip install packaging
無事に動く。
前のバージョンに戻す
3.4.3に戻してる人がいたのでそれでやってみる
pip install webdriver-manager==3.4.3
これも動く。
終わりに
いつもpip installでバージョン指定せずにインストールするばかりに、最新のバグに遭遇することが多いから、1つ前の安定したものをインストールするようにしようかな。
issueで話していることについて、自分もpackageを開発したことがあるから内容がスッと入ってきた。
(コロコロナちゃん)
すぐに修正が入ると思うけど、びっくりしたので記事に残しておく。
原因の原因
ユーザーがあるパッケージをインストールしたときに、そのパッケージで使われている依存したパッケージを自動的にインストールさせるにはsetup.pyにその記述が必要になる。
実際にwebdriver-managerのソースコードを見てみると、
#
# 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に上がっているものはすでに修正されてた。
はよpypiに載せてや。
原因の原因の原因
気になったので、このpackagingが何に使われているか調べてみた。
from packaging import version
必要なのはversionってやつで、こいつがバージョンのパースをしてくれるみたいなので比較とかで使えるっぽい。
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)なるものが変わったらしくて、
if version.parse(browser_version) < version.parse("106.0.5249.61") :
os_type = os_type.replace("mac_arm64", "mac64_m1")
のように変更する必要があるみたい。
このos_typeが何なのかというと、chromedriverのダウンロード画面に行けばわかる。
確かに、
chromedriver_mac64_m1.zipから
chromedriver_mac_arm64.zipに変更されている。
こんな些細な変更が、
get_url()関数で正しいurlを返すことができず、結果ChromeDriverがインスタンスを生成できないってことになるんだね。
def get_url(self):
...
...
return f"{self._url}/{browser_version}/{self.get_name()}_{os_type}.zip"
以上、自分がスッキリしただけ。

