seleniumで使用するWebDriverの3種類の取得方法

# 投稿の理由
>GoogleChrome115へのバージョンアップにより、しばらくseleniumが使えなかった。
最初は訳も分からず焦ったが、「webdriver-manager」はすぐに修正されたので、問題はなかったが、「chromedriver_binary」と「WebDriverのパスを指定」は手動での修正が必要で戸惑ったことから、３種類の取得方法と使用方法をまとめて記録しておこうと思った。
当たり前のことなのかもしれないが、「selenium」を初めて勉強した時迷ったままだったので、これから勉強する人には必要かもと思い整理してみた。
---
#  私の環境
>iMacOS vetura 13.2
プロセッサ　Intel Core i5
chromedriver-binary　116.0.5845.96.0
PyQt6　6.5.2
selenium　4.11.2
GoogleChrome　116.0.5845.96.0
---
# ブラウザを自動化するためのツール(webdriver)種類
**私の場合は、趣味でpythonを勉強している中で、seleniumに興味を持っただけなので、今では「webdriver-manager」を知っていれば十分と思っています。**
seleniumの勉強を始めた最初の頃、色々とググったせいで混乱してしまって、programを組む都度、最初は「WebDriverのパス」で躓き、次に「chromedriver_binary」で助かり、最後に「webdriver-manager」 を使う方法を知ったので、program毎にバラバラになってしまった経験があるので、ここで整理するのもいいかなっと思って記録します。

>**01_webdriver-manager を使う方法**
	特定のバージョンのChromedriverを自動的にダウンロードして管理するためのツール	
	このツールを使用すると、必要なバージョンのChromedriverが自動的にダウンロード
	され、実行環境に合わせてPATHに追加されます。
	欠点：今は感じない
**02_chromedriver_binary　を使う方法**
	ChromedriverバイナリをPythonプロジェクト内に含めることで、手動で
	ChromedriverをダウンロードしたりPATHに追加したりする手間を省くためのツール
	です。	
	欠点：新しいバージョンへのインストールの仕直しがある（今回もそうだった）
**03_WebDriverのパスを指定する方法**
	特定のバージョンのWebDriverを使用したい場合や、プロジェクト内にWebDriverを
	含めたくない場合に適しています。
	ソースコード内に明示的にどのバージョンのWebDriverを使用しているかを示すことが
	できます。
	欠点：driverを取得して都度入れ替える（今回もそうだった）
---
### まずは、GoogleChromeのversionの確認をしておきます。知ってる方は飛ばしてください。
>１、GoogleChromeの右上の記号をクリックします。」
<img title="01_versionの確認01" alt="01_versionの確認01" width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/93f08f19-b1ca-8d95-394b-c63230d0b5d1.jpeg">


>２、設定をクリックします。
<img title="02_versionの確認" alt="02_versionの確認" width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/f07fbd40-f304-ab87-048d-37a4d68217a9.jpeg">

>３、「chromeについて」をクリックします。
<img title="03_versionの確認" alt="03_versionの確認" width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/59664949-cc42-7dd9-b48d-addaf7403564.jpeg">

>４、ここに表示されるのが、最新のversionです。（pip list でchromedriver-binaryのVersionが一致しているか確認などに使います。）
<img title="04_versionの確認" alt="04_versionの確認" width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/f08c1c0f-9879-3ec6-40c6-0be942836ecd.jpeg">

# ３種類のwebdriberの取得方法
### 01_webdriver-managerの取得
>まず、webdriver-managerをターミナルでインストールします。
```python
% python3 -m pip install webdriver-manager
```
>次に、Pythonスクリプト内でwebdriver-managerを使用してChromedriverを取得します。（詳しくは後述する「programへの記述」で記載）
```python
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager  # ChromeDriverManagerをインポート
```
>pip listで確認してみてください。
<img title="ErrorMessage" alt="ErrorMessage" width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/4f775001-a032-4793-712b-e6890d8c843e.png">

### 02_chromedriver_binaryの取得
>まず、chromedriver_binaryをインストールします。ターミナルで以下のコマンドを実行します：
```python
pip install chromedriver-binary
```
pip listで確認してみてください。
<img title="pip listで確認" alt="pip listで確認" width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/34ebf0a8-b6b3-209b-b0d1-01fe73d30d3e.png">

>次に、Pythonスクリプト内でchromedriver_binaryを使用してChromedriverを取得します。（詳しくは後述する「programへの記述」で記載）
```python
from selenium import webdriver
import chromedriver_binary  # chromedriver_binaryをインポート
```
### 03_WebDriverのパスの取得
>まず、GoogleChromeのaddress berに<font color="green">「chrome://version」</font>と入力します。
<img title="ErrorMessage" alt="ErrorMessage" width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/955519c5-bc42-758e-b822-1ecf89d96661.jpeg">


>次に、表示される<font color='green'>「実行ファイルのパス」</font>の〜/MacOS/までをメモしておきます。（詳しくは後述する「programへの記述」で記載）
<img title="ErrorMessage" alt="ErrorMessage" width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/038714c6-074e-3a3b-833f-e3232f83afe7.jpeg">


---
# programへの記述
seleniumを使って、「”python”についてググる」programを記述してみます。
違う点は"import time" の次のcodeです。そこに以下のそれそれのcodeを記述して試してください。
結果は全て同じになる筈です。


### 01_webdriver-managerの記述例
```python
# Selenium WebDriver用のドライバーを自動的にダウンロードして管理するためのツール(パッケージ)
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
```
### 02_chromedriver_binaryの記述例
```python
# Chromedriverを簡単にインストール・管理できるようにするためのパッケージ
#Driverの場所:/Users/xxxxxxx/.pyenv/versions/3.10.4/lib/python3.10/site-packages/chromedriver_binary

import chromedriver_binary

# Chromedriverを使用してChromeブラウザを起動
driver = webdriver.Chrome()
```
### 03_WebDriverのパスの記述例
```python
# Chrome WebDriverのパスを指定してServiceオブジェクトを作成（GoogleChromeのアドレスバーへ「chrome://version」と入力）
driver_path = '/Applications/Google Chrome.app/Contents/MacOS/chromedriver'# <-ここにメモしたパスを記述/MacOS/の次は「chromedriver」と記述するのが決まりらしい。

# Serviceを使用してWebDriverを起動
driver = webdriver.Chrome(service=ChromeService(driver_path))
```

## では、programの全体を表示します。
“python”についてググた内容がターミナルに表示されるprogramです。
```python
# googleの検索窓に「"pythoneについて"と入力してググる」自動化program
# -----------------------------------------------------------
# seleniumオブジェクトのimport
# 様々なブラウザを制御するためのクラスを提供(主にWebアプリケーションのテストやスクレイピングなどに使用するモジュール)
from selenium import webdriver
# find_element() メソッドを呼び出す際に要素を見つける方法を指定するために使用
from selenium.webdriver.common.by import By
# 要素が特定の条件を満たすまで待機するために使用
from selenium.webdriver.support.ui import WebDriverWait
# WebDriverWait と組み合わせて、要素が特定の条件を満たすまで待機するために使用
from selenium.webdriver.support import expected_conditions

# Serviceクラスは、ブラウザのドライバーを実行するためのサービスを管理するためのクラス
# 通常、直接使用することはありませんが、カスタム設定が必要な場合に便利
from selenium.webdriver.chrome.service import Service as ChromeService
# -----------------------------------------------------------
import time # すべてのページが表示されるまで待機
# ------------------------------------------------------
#この部分がdriverの取得方法によって変わります。　　　　　　　　　|
#| 上のcodeをここにCopy and Paste してください。            |
#|                                                     |
#|                                                     |
# ------------------------------------------------------

# ヘッドレスモード設定
options = webdriver.ChromeOptions()
options.add_argument("--headless")

driver.get('https://google.com')
# ------------------------------------------------------
# 検索文字を入力するためのxpath
xpath = '//*[@id="APjFqb"]'
search = "python" #input(‘検索する内容：')　# <- “python"　# を削除すれば入力方式に変更できます。

# タイムアウトを10秒に設定
wait = WebDriverWait(driver, 10)

# 検索文字列を入力
input = driver.find_element(By.XPATH,xpath)#<-selenium3以降
input.send_keys(search + 'について')
input.submit()

# すべてのページが表示されるまで2秒待機
time.sleep(2)
#ターミナルへ表示
for elem_h3 in driver.find_elements(By.XPATH,'//a/h3'):
    elem_a = elem_h3.find_element(By.XPATH,'..')
    print(elem_h3.text)
    print(elem_a.get_attribute('href'))
    print('')
    print('-'*50)
#　このドライバを終了し、開かれていたすべての関連ウィンドウを閉じる
driver.quit()
```

---

# 「chromedriver_binary」でエラーが出た場合の対処
>下記のサイトを参照してください。


https://qiita.com/ti104110/items/3b040a5cd15b004d35b8


# 「WebDriverのパスを指定」でエラーが出た場合の対処
>下記のサイトを参照してください。


https://qiita.com/ti104110/items/075e609627b5d12c0ea7

# 最後に
ChatGPTに次の質問をしてみました。
**GoogleChromeのDriverを取得する次の方法の利点と欠点を教えて
「webdriver-manager」
「chromedriver_binary」
「WebDriverのパスを指定する」**

**ChatGPTの回答**
**webdriver-managerを使用する方法：**
>**<font color="red">利点：</font>**
自動的に特定のバージョンのDriverをダウンロードして管理できるため、バージョンの整合性が保たれる。
インストールやアップデートが簡単に行える。
プロジェクト内にDriverのバイナリを含める必要がないため、プロジェクトサイズが大きくならない。
>**<font color="blue">欠点：</font>**
外部の依存モジュール（webdriver_manager）を使用するため、環境によっては追加の依存関係が必要。インターネット接続が必要な場合があり、オフライン環境では使用しづらいかもしれない。

**chromedriver_binaryを使用する方法：**
>**<font color="red">利点：</font>**
必要なバージョンのDriverを自動的にダウンロードして管理できる。
プロジェクト内にDriverのバイナリを含める必要がないため、プロジェクトサイズが大きくならない。
インストールやアップデートが簡単に行える。
>**<font color="blue">欠点：</font>**
外部の依存モジュール（chromedriver_binary）を使用するため、環境によっては追加の依存関係が必要。インターネット接続が必要な場合があり、オフライン環境では使用しづらいかもしれない。

**WebDriverのパスを指定する方法：**
>**<font color="red">利点：</font>**
プロジェクト内に特定のバージョンのDriverを含めたい場合に適している。
インターネット接続が不要で、オフライン環境でも使用できる。
>**<font color="blue">欠点：</font>**
特定のバージョンのDriverを手動でダウンロードして管理する必要がある。
バージョンの整合性を手動で確保する必要があり、手間がかかる。
プロジェクトサイズが大きくなる可能性がある。

>選択する方法は、プロジェクトの要件や制約によって異なります。
webdriver-managerやchromedriver_binaryを使用する方法は、特に継続的なバージョン管理と簡潔なコードを実現したい場合に有用です。
一方で、特定のDriverバージョンを明示的に管理するか、オフライン環境を考慮する必要がある場合には、WebDriverのパスを指定する方法が適しているかもしれません。