🦥

[Python] seleniumの仕様が変わっていた!?(2023/06時点)

2023/06/25に公開
2

はじめに

先日、社内のテストでログイン動作がめんどくさいと感じ
1~2 年前の記事を参考にしながら selenium で自動ログインスクリプトを作成しました。

しかし、いつからの selenium のアップデートから記述の仕様が多く変わって苦労したので、
躓いた変更点を紹介します。

対象読者

  • selenium 初学者

この記事でわかること

  • 仕様変更後の selenium が理解できる

前提条件

  • Python 3.10.11
  • selenium 4.10.0
  • webdriver-manager 3.8.6

サンプルコード

1. webdriver.Chrome('./chromedriver.exe')が使えない

再現方法を紹介します。

  1. ファイル構成
    chromedriver.exeをダウンロードして下記の通りに配置します。
.
├── chromedriver.exe
└── error_selenium001.py
  1. webdriver.Chrome('./chromedriver.exe')を含めたスクリプトを作成する
    Google の検索ページを表示するスクリプトを作成
error_selenium001.py
from selenium import webdriver

# ブラウザインスタンス
driver = webdriver.Chrome('./chromedriver.exe')
#特定のURLへ移動
driver.get('https://www.google.com/')

#最大待機時間を10秒にセット
driver.implicitly_wait(10)
  1. スクリプトを実行する
$ python error_selenium001.py
Traceback (most recent call last):
  File "C:\Users\xxxxxxxx\Work\Zenn\error_selenium001.py", line 7, in <module>
    driver = webdriver.Chrome('./chromedriver.exe')
  File "C:\Users\xxxxxxxx\AppData\Local\Programs\Python\Python310\lib\site-packages\selenium\webdriver\chrome\webdriver.py", line 49, in __init__
    super().__init__(
  File "C:\Users\xxxxxxxx\AppData\Local\Programs\Python\Python310\lib\site-packages\selenium\webdriver\chromium\webdriver.py", line 60, in __init__
    ignore_proxy=self.options._ignore_local_proxy,
AttributeError: 'str' object has no attribute '_ignore_local_proxy'

じゃあどうしたらいいの?

webdriver.Chrome('./chromedriver.exe')webdriver.Chrome()に変更します

error_selenium001.py
from selenium import webdriver

# ブラウザインスタンス
- driver = webdriver.Chrome('./chromedriver.exe')
+ driver = webdriver.Chrome()
#特定のURLへ移動
driver.get('https://www.google.com/')

#最大待機時間を10秒にセット
driver.implicitly_wait(10)

2. webdriver.Chrome(ChromeDriverManager().install())が使えない

再現方法を紹介します。

  1. webdriver.Chrome(ChromeDriverManager().install())を含めたスクリプトを作成します
    Google の検索ページを表示するスクリプトを作成
error_selenium002.py
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

# ブラウザインスタンス
driver = webdriver.Chrome(ChromeDriverManager().install())
#特定のURLへ移動
driver.get('https://www.google.com/')

#最大待機時間を10秒にセット
driver.implicitly_wait(10)

  1. スクリプトを実行する
$ python error_selenium002.py
[WDM] - Downloading: 100%|##########| 6.30M/6.30M [00:01<00:00, 4.48MB/s]
Traceback (most recent call last):
  File "C:\Users\xxxxxxxx\Work\Zenn\error_selenium002.py", line 7, in <module>
    driver = webdriver.Chrome(ChromeDriverManager().install())
  File "C:\Users\xxxxxxxx\AppData\Local\Programs\Python\Python310\lib\site-packages\selenium\webdriver\chrome\webdriver.py", line 49, in __init__
    super().__init__(
  File "C:\Users\xxxxxxxx\AppData\Local\Programs\Python\Python310\lib\site-packages\selenium\webdriver\chromium\webdriver.py", line 60, in __init__
    ignore_proxy=self.options._ignore_local_proxy,
AttributeError: 'str' object has no attribute '_ignore_local_proxy'

じゃあどうしたらいいの?

  1. from webdriver_manager.chrome import ChromeDriverManagerは不要なので削除します
  2. webdriver.Chrome(ChromeDriverManager().install())webdriver.Chrome()に変更します
error_selenium002.py
from selenium import webdriver
- from webdriver_manager.chrome import ChromeDriverManager

# ブラウザインスタンス
- driver = webdriver.Chrome(ChromeDriverManager().install())
+ driver = webdriver.Chrome()
#特定のURLへ移動
driver.get('https://www.google.com/')

#最大待機時間を10秒にセット
driver.implicitly_wait(10)

3. find_element_by_XXX系が使えない

再現方法を紹介します。

  1. driver.find_element_by_id("username")を含めたスクリプトを作成します
error_selenium003.py
from selenium import webdriver

# ブラウザインスタンス
driver = webdriver.Chrome()
#特定のURLへ移動
driver.get('https://www.google.com/')

#最大待機時間を10秒にセット
driver.implicitly_wait(10)

username = driver.find_element_by_id("username")
  1. スクリプトを実行する
$ python error_selenium003.py
Traceback (most recent call last):
  File "C:\Users\xxxxxxxx\Work\Zenn\error_selenium003.py", line 11, in <module>
    username = driver.find_element_by_id("username")
AttributeError: 'WebDriver' object has no attribute 'find_element_by_id'

じゃあどうしたらいいの?

  1. find_elementの引数にByが必要なためfrom selenium.webdriver.common.by import Byを import します
  2. driver.find_element_by_id("username")driver.find_element(By.ID, "username")に変更します
error_selenium003.py
from selenium import webdriver
+ from selenium.webdriver.common.by import By

# ブラウザインスタンス
driver = webdriver.Chrome()
#特定のURLへ移動
driver.get('https://www.google.com/')

#最大待機時間を10秒にセット
driver.implicitly_wait(10)

- username = driver.find_element_by_id("username")
+ username = driver.find_element(By.ID, "username")

対比表

検索手段 旧記述 新記述
id .find_element_by_id("id") .find_element(By.ID, "id")
name .find_element_by_name("name") .find_element(By.NAME, "name")
xpath .find_element_by_xpath("xpath") .find_element(By.XPATH, "xpath")
リンクのテキスト .find_element_by_link_tsxt("link text") .find_element(By.LINK_TEXT, "link text")
リンクのテキスト(部分一致) .find_element_by_partial_link_text("partial link text") .find_element(By.PARTIAL_LINK_TEXT, "partial link text"))
タグ名 .find_element_by_tag_name("tag name") .find_element(By.TAG_NAME, "tag name")
クラス名 .find_element_by_class_name("class name") .find_element(By.CLASS_NAME, "class name")
css セレクタ .find_element_by_css_selector("css selector") .find_element(By.CSS_SELECTOR, "css selector")
GitHubで編集を提案

Discussion

戸田広戸田広

1と2は、Selenium3からSelenium4になるときにwebdriver.Chrome()の引数の型が変わっただけなので、引数の記述を無くしてデフォルトの値にするのを解決方法とするのはあまり良くないです。

Selenium 3: https://github.com/SeleniumHQ/selenium/blob/selenium-3.150.0/py/selenium/webdriver/chrome/webdriver.py#L34-L37
chromedriverのパス文字列は第1引数のexecutable_pathに渡すことになっていました。

Selenium 4: https://github.com/SeleniumHQ/selenium/blob/selenium-4.10.0/py/selenium/webdriver/chrome/webdriver.py#L29-L34
chromedriverのパス文字列はServiceオブジェクト経由で渡すように変わりました。

日本語の記事が必要でしたら私がCodeZineに書きましたのでご覧ください。 https://codezine.jp/article/detail/15379?p=2

ふるた なおき🥝ふるた なおき🥝

コメントありがとうございます。
紹介して頂いた記事を参考にしながら加筆したいと思います。
ありがとうございます!