Python Selenium PermissionError: [WinError 5] アクセスが拒否されました 解決法

- Python -
2023.09.03
Python[パイソン]

以下3点を全て満たす場合、本記事が参考になる可能性があります。

  1. ライブラリ webdriver-manager v4.0.0 を利用している
  2. Windowsを利用している
    → 自分のMac環境では再現しないエラー
  3. ChromeDriverを同時に4つ以上起動しようとしている

そもそもwebdriver-managerを利用していないかたは、本記事の想定する事象とは別と考えられるため、お役に立てませんm(_ _)m

・・・という前提をおいたうえで、まずはぼくが直面したエラーから。

Traceback (most recent call last): File "C:\Users\me\AppData\Local\Programs\Python\Python39\lib\site-packages\webdriver_manager\core\file_manager.py", line 65, in __extract_zip archive.extractall(to_directory) File "C:\Users\me\AppData\Local\Programs\Python\Python39\lib\zipfile.py", line 1633, in extractall self._extract_member(zipinfo, path, pwd) File "C:\Users\me\AppData\Local\Programs\Python\Python39\lib\zipfile.py", line 1687, in _extract_member open(targetpath, "wb") as target: PermissionError: [Errno 13] Permission denied: 'C:\\Users\\me\\.wdm\\drivers\\chromedriver\\win64\\116.0.5845.111\\chromedriver-win32\\chromedriver.exe' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Users\me\Desktop\program\selenium-test.py", line 101, in driver = driver_setup() File "C:\Users\me\Desktom\program\program\selenium-test.py", line 92, in driver_setup driver = webdriver.Chrome(ChromeDriverManager().install(),options=options) File "C:\Users\me\AppData\Local\Programs\Python\Python39\lib\site-packages\webdriver_manager\chrome.py", line 40, in install driver_path = self._get_driver_binary_path(self.driver) File "C:\Users\me\AppData\Local\Programs\Python\Python39\lib\site-packages\webdriver_manager\core\manager.py", line 41, in _get_driver_binary_path binary_path = self._cache_manager.save_file_to_cache(driver, file) File "C:\Users\me\AppData\Local\Programs\Python\Python39\lib\site-packages\webdriver_manager\core\driver_cache.py", line 54, in save_file_to_cache files = self.unpack_archive(archive, path) File "C:\Users\me\AppData\Local\Programs\Python\Python39\lib\site-packages\webdriver_manager\core\driver_cache.py", line 49, in unpack_archive return self._file_manager.unpack_archive(archive, path) File "C:\Users\me\AppData\Local\Programs\Python\Python39\lib\site-packages\webdriver_manager\core\file_manager.py", line 57, in unpack_archive return self.__extract_zip(archive_file, target_dir) File "C:\Users\me\AppData\Local\Programs\Python\Python39\lib\site-packages\webdriver_manager\core\file_manager.py", line 81, in __extract_zip os.replace(source, destination) PermissionError: [WinError 5] アクセスが拒否されました。: 'C:\\Users\\me\\.wdm\\drivers\\chromedriver\\win64\\116.0.5845.111\\chromedriver-win32\\chromedriver.exe' -> 'C:\\Users\\me\\.wdm\\drivers\\chromedriver\\win64\\116.0.5845.111\\chromedriver.exe'

このエラーメッセージも合致する場合、ぼくと同じ事象の可能性がかなり高いかと。

webdriver-managerを使うのをやめて、Selenium Managerを使うことでこのエラーは解決。

現在selenium v3を使っている場合、selenium v4.6以上へ更新が必要。

※ 環境によっては、最新版(v4.12〜)への更新が必要

今までずっとChromeDriverの自動更新にはwebdriver-managerが必須だと思ってたんですが、

selenium v4.6からselenium自体にChromeDriver自動更新機能である「Selenium Manager」が搭載されていたんですね。

参考selenium.dev:Introducing Selenium Manager

Python SeleniumでPermissionError: [WinError 5] アクセスが拒否されました。

【原因】webdriver-managerで不具合(仕様?)

webdriver-managerv4.0.0でChromeDriverを4つ以上同時に起動する。

これがトリガーとなってPermissionErrorが出てしまうとissueで報告あり。

参考GitHub - webdriver-manager:
Running more than 3 threads causes permission issue #593

やはりぼくと同じようにWindowsでの事象のようです。

Macではいくつプログラムを重複起動してもエラーは出ません。

stack overflowでも全く同じ事象の投稿あり、こちらもWindows環境。

参考stack overflow:
Permission Error when opening more than 3 selenium chrome driver at one time

ぼくはWindowsのタスクスケジューラでwebdriver-managerv4.0.0を使った5つのプログラムを定期実行しているときにこの事象が出始めたので、まさに同じ事象。

解決法:webdriver-managerを使わない(Selenium Managerを使う)

webdriver-managerv4.0.0を使う限り、4つ以上同時起動できない問題は解決しません。

webdriver-managerの記述は削除、そしてSeleniumに内蔵されているSelenium Managerという機能に頼ってChromeDriver自動更新を実現するよう書き換えることで対応しました。

正確には...

pytest-xdistを使えば解決するよ」とwebdriver-manager開発者のSergey氏がコメントしてGitHub issueがクローズされました。

が、webdriver-managerと組み合わた使い方などについては何もなく、他ユーザーからも「それでクローズはないでしょ...」とコメントされている状況。

同時に4つ以上プログラムを起動する可能性のあるかたは、webdriver-managerを使う選択肢が残ってないのでは...と考えます。

Seleniumについて調べていると、

いつの間にかSelenium自体にChromeDriver自動更新機能が搭載されてるじゃん。

これ、もうwebdriver-managerを使う必要なくない...?

と思ったのがキッカケ。

これで、4つ以上同時起動しても「PermissionError: [WinError 5] アクセスが拒否されました。」エラーは起きなくなりました。

※ 今後webdriver-managerのアップデートによって解決する可能性があります

・・・

以降、webdriver-managerを使わないコードへの修正例を紹介します。

あなたの環境に合わせて読み替えて修正してエラーが解消するかどうか試してみてください。

1. Selenium バージョンを最新(4.6以上)に更新

まず、現Seleniumのバージョンが4.6以上かどうかを確認します。

> pip show selenium
Name: selenium
Version: 3.141.0 ← 更新が必要
Version: 4.5.0 ← 更新が必要
Version: 4.6.0 ← 更新不要(エラーになる場合は更新)
Version: 4.12.0 ← 更新不要
Summary:
Home-page: https://www.selenium.dev
・・・

現バージョンを確認してすでに4.6以上で動いているかたは、本手順をスキップします。

・・・

要更新の場合、以下コマンドでSeleniumを最新版へ更新。

pip install -U selenium

> pip install -U selenium
Requirement already satisfied: selenium in /usr/local/lib/python3.9/site-packages (3.141.0)
Collecting selenium
・・・省略・・・
Uninstalling selenium-3.141.0:
Successfully uninstalled selenium-3.141.0
Successfully installed selenium-4.12.0

上記のように古いバージョンがアンインストールされ、新しいバージョンがインストールが成功すればOK。

▼切り戻し方法

もし元のバージョンに戻す場合、以下のようにバージョン指定をしてpip installするだけ。

pip install selenium==3.141.0

2. Selenium v.4の記法に書き換え

手順1.でSeleniumバージョンを3→4へ上げたかたのみ、この手順を実行します。

最初からv4.0以上を使っていたかたは、本手順はスキップしてOK。

Selenium v3とv4でfind_element系メソッドの記法が少し違うため、更新直後からエラーが出てしまいます。

BEFORE → AFTERへ書き換えましょう。Byインポートを忘れずに。

Python# BEFORE
find_element_by_id("id")
find_element_by_name("name")
find_element_by_xpath("xpath")
find_element_by_link_text("link text")
find_element_by_partial_link_text("partial link text")
find_element_by_tag_name("tag name")
find_element_by_class_name("class name")
find_element_by_css_selector("css selector")


# AFTER
from selenium.webdriver.common.by import By

find_element(By.ID, "id")
find_element(By.NAME, "name")
find_element(By.XPATH, "xpath")
find_element(By.LINK_TEXT, "link text")
find_element(By.PARTIAL_LINK_TEXT, "partial link text")
find_element(By.TAG_NAME, "tag name")
find_element(By.CLASS_NAME, "class name")
find_element(By.CSS_SELECTOR, "css selector")

参考selenium-python.readthedocs.io:Locating Elements

3. webdriver-managerを使わないように書き換える

▼このように書いていたのを、

Python# BEFORE
driver = webdriver.Chrome(ChromeDriverManager().install())

▼こうします。

Python#AFTER
driver = webdriver.Chrome()

optionsを指定している場合は今までどおり引数として放り込むだけ。

Python#AFTER
driver = webdriver.Chrome(options=options)

これで、4つ以上プログラムを同時起動してもPermissionError: [WinError 5]が出なくなりました。

v4.6〜4.10でエラーが出る場合

4.6〜4.10を使っているのに、webdriver.Chrome()で以下のような「chromedriverのパスを指定しろ」エラーになってしまう場合。

▼selenium 4.6実行例

> python test-selenium.py

thread 'main' panicked at 'Downloaded file cannot be uncompressed (xml extension)', src/files.rs:46:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
・・・省略・・・
raise WebDriverException(f"Unsuccessful command executed: {args}")
selenium.common.exceptions.WebDriverException: Message: Unsuccessful command executed: ('/usr/local/lib/python3.9/site-packages/selenium/webdriver/common/macos/selenium-manager', '--browser', 'chrome')
・・・省略・・・
During handling of the above exception, another exception occurred:
raise WebDriverException(
selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://chromedriver.chromium.org/home

この場合、以下コマンドでSeleniumを最新版(本記事公開時点でv4.12)に更新してください。

pip install -U selenium

これでドライバーのパスを記載しなくても起動するようになるはずです。

 

・・・以下、蛇足・・・

webdriver.Chrome()だけでホントに適切なバージョンのChromeDriverが自動的にダウンロードされんの?

と思うかもしれません。

selenium v4.5までは、①ChromeDriverをダウンロードする ②ChromeDriverのパスを以下のように指定する、という作業が必要でした。

Python# ChromeDriverのパス
driver_path = "driver/chromedriver.exe"

service = Service(executable_path=driver_path)
driver = webdriver.Chrome(service=service)

これが面倒だから今までwebdriver-managerを使っていたのですが。

selenium v4.6から、この↓1行で自動的にChromeに適合したChromeDriverがダウンロードされます(裏側で自動で動くSelenium Managerという機能のおかげ)。

Pythondriver = webdriver.Chrome()

メモ:

Selenium Managerは、本記事公開時点のselenium最新版4.12.0で"ベータ版につき今後変更可能性あり"とコメントが記載されています。念の為。

selenium_manager.pyclass SeleniumManager:
    """Wrapper for getting information from the Selenium Manager binaries.

    This implementation is still in beta, and may change.
    """

    @staticmethod
    def get_binary() -> Path:
        ・・・省略・・・

参考GitHub:selenium_manager.py ソースコード

↑TOP