結論
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"
以上、自分がスッキリしただけ。