f14: selenium / chrome webdriver 動作環境の検証

.
selenium の chrome webdriver + headless
を用いたスクレイピング手法については、
多くの方が情報共有をされておりますので、
実現の詳細は他の方の記事におまかせし、

いくつかの環境で試してみましたので、
動作検証結果をメモします

※ OK 環境、NG 環境、動作不安定環境、ともに
実際の検証結果ですが、OS や 各々の環境により、
必ずしも同じ結果になるとは断定できませんので、
参考程度で捉えてください


※ python は、3.x 系です

※ google chrome + webdriver + headlees で実施してます

※ サンプルとしてヤフー天気の大阪の気温を取得してます

```python:sample1.py
driver.get("https://weather.yahoo.co.jp/weather/")

highs = driver.find_elements(By.XPATH, '//*[@id="map"]/ul/li[8]/a/dl/dd/p[2]/em[1]')
lowss = driver.find_elements(By.XPATH, '//*[@id="map"]/ul/li[8]/a/dl/dd/p[2]/em[2]')

print('osaka temp highest: ' + highs[0].text)
print('osaka temp lowests: ' + lowss[0].text)
```


---

### **[ 0. メニュー ]**

**(01) wsl2 + ubuntu**
**(02) レンタルサーバー**
**(03) Google Colaboratory (SaaS)**
**(04) linux ネイティブ**
**(05) heroku (PaaS)**

---
### **[ 1. 食感 ]**

.
**---- (01) wsl2 + ubuntu -------------------------**

※ Docker ではなく、
　wsl2 上で起動させる ubuntu 環境

**・動作：三角 (△)**
**・安定性：ばつ (×)**

**・メリット：**　ubuntu 導入は簡単

**・デメリット：**
　windows の OS や ビルドの関係、
　windows の管理者権限関連などにより、
　wsl2 上の linux 動作に制約があるせいか、
　構築環境によっては、動作が安定しない、
　またはエラーにより、webdriver がまともに機能しない
　(動作 OK 環境もありますが、wsl2 全体としての評価)

　windows 11 以降の将来は、
　安定していくのかもしれませんが、
　少なくとも windows 10 ベースの環境では
　安定動作はあまり期待はできませんでした

.
**---- (02) レンタルサーバー ----------------------**

**・動作：ばつ (×)**
**・安定性：省略 (ー)**

**・メリット：** なし

**・デメリット：**
　ばつ (×)と断定していいのか
　というところもありますが、
　レンタルサーバー系は、基本的に
　権限問題がついてまわるので、
　アプリのインストールや設定が
　できない可能性が高いです

.
**---- (03) Google Colaboratory (SaaS) ------------**

※ 無料プランで実施

**・動作：まる (〇)**
**・安定性：三角 (△)**

**・メリット：** ほぼ環境構築不要、
　Google Drive 上で、お手軽に導入できる

**・デメリット：**
　通常の linux 系と違い、使い勝手にクセがある
　・実行はコンソール的な対話型で使用し、
　　無料プランでは自動実行は使えない
　・pip が使いにくい
　・ファイル管理が普通にできないため使いにくい

　今回の検証では、Gドライブのマウント時、
　毎回 Google アクセス要求の承認で処理が止まる
　(手動にて承認後、処理は続行されます)
　(設定により回避できるのかもしれません)

　一部の pip インストールや Gドライブマウントにて
　時間がかかり、かつ、python の実行においても、
　ブラウザ上で操作していること
　および、google 共有スペースで実行されている
　ためか処理が遅いです

　そのためか、page crash や、time out、
　503 などのエラーが発生することがあります

　Google Colaboratory は、
　簡易的な python 実行環境の印象です

.
**---- (04) linux ネイティブ ----------------------**

※ vps もネイティブ扱いにしてます

**・動作：まる (〇)**
**・安定性：まる (〇)**

**・メリット：** さすがの linux ネイティブで、
　動作も安定性も文句なし！

　cron による自動定期実行もあわせれば快適！

**・デメリット：**
　強いてあげるなら、linux の通常構築が必要、
　または vps 契約が必要、くらいです

.
**---- (05) heroku (PaaS) --------------------------**

**・動作：まる (〇) のようです**
**・安定性：まる (〇) のようです**

　heroku は未検証なので、
　ここにあげるべきではないのですが、
　ネット上の記事を見ている限り、
　chrome + webdriver + headless は、
　動作、安定性、ともに、良さそうです


---
### **[ 2. 味見 ]**

.
**---- (01) wsl2 + ubuntu -------------------------**


==========================================
**環境1：windows 11 pro + wsl2 + ubuntu 20.04**


　**FUJITSU デスクトップ PC
　core i5-9500 3.00GHz 6コア 6スレッド
　8 GB ram / SSD 256GB**

**・動作：まる (〇)**
**・安定性：まる (〇)**

```bash:
> winver
21H2 (OS build 22000.1219)
```

```bash:
$ google-chrome --version
Google Chrome 105.0.5195.102
```

```bash:
$ pip list
chromedriver-binary 105.0.5195.52.0
selenium 4.4.3
urllib3 1.26.12
```

```python:sample1.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary

from selenium.webdriver.common.by import By

opts = Options()
opts.add_argument('--headless')
opts.add_argument('--no-sandbox')
opts.add_argument('--disable-dev-shm-usage')

driver = webdriver.Chrome(options=opts)
```

-> windows 11 + このビルドでは、
　特にエラーもなく安定して動作しました
　ただ、windows 11 だから OK とは断定できません

==========================================
**環境2：windows 10 pro + wsl2 + ubuntu 20.04**

　**surface pro7
　core i5-1035G4 1.10GHz 4コア/8スレッド
　8 GB ram / SSD 256GB**

**・動作：三角 (△)**
**・安定性：ばつ (×)**

```bash:
> winver
21H2 (os build 19044.2251)
```

```bash:
$ google-chrome --version
Google Chrome 90.0.4430.72
```

```bash:
$ pip list
chromedriver-binary 90.0.4430.24.0
selenium 4.4.3
urllib3 1.26.12
```

```python:sample1.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary

from selenium.webdriver.common.by import By

opts = Options()
opts.add_argument('--headless')
opts.add_argument('--no-sandbox')
opts.add_argument('--disable-dev-shm-usage')

driver = webdriver.Chrome(options=opts)
```

-> 起動ごとに、以下の 3パターンのどれかになります

Google Chrome と chromedriver-binary の
バージョンも ver.90 - ver.105 までの
いくつかをそれぞれ入れなおして試しましたが、
エラーがなくなることはなかったです

**結果1: OK**
osaka temp highest: 12
osaka temp lowests: 6

**結果2: NG**
Traceback (most recent call last):
  File "sample1.py", line 27, in <module>
    print('osaka temp highest: ' + highs[0].text)
IndexError: list index out of range

**結果3: NG**
selenium.common.exceptions.WebDriverException: Message: unknown error: session deleted because of page crash
from unknown error: cannot determine loading status from tab crashed
  (Session info: headless chrome=90.0.4430.72)

==========================================
**環境3：windows 10 home + wsl2 + ubuntu 20.04**

　**surface pro7
　core i7-1065G7 1.3GHz 4コア/8スレッド
　16 GB ram / SSD 256GB**

**・動作：ばつ (×)**
**・安定性：ばつ (×)**

```bash:
> winver
21H2 (os build 19044.2251)
```

```bash:
$ google-chrome --version
Google Chrome 99.0.4844.84
```

```bash:
$ pip list
chromedriver-binary 99.0.4844.51.0
selenium 4.4.3
urllib3 1.26.12
```

```python:sample1.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary

from selenium.webdriver.common.by import By

opts = Options()
opts.add_argument('--headless')
opts.add_argument('--no-sandbox')
opts.add_argument('--disable-dev-shm-usage')

driver = webdriver.Chrome(options=opts)
```

-> 環境2 同様、色々な chrome バージョンを試しましたが、
主には以下のエラーが出て、動作 OK となりませんでした

**NG：** selenium.common.exceptions.WebDriverException: 
Message: unknown error: DevToolsActivePort file doesn't exist

options.add_argument("--remote-debugging-port=9222") 
のような未割当ポートの指定を追加するとよいという記事も
拝見し、試したりもしましたが、

そもそも wsl2 / ubuntu は、firewall(ufw) 設定されておらず

```bash:
$ sudo apt -y install ufw
```
ufw を入れてみても、

```bash:
$ sudo ufw status
ERROR: problem running iptables: iptables v1.8.4 (legacy): 
can't initialize iptables table `filter': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.
```
などとなり、

windows 側で、WSL と 管理者権限で、一部 linux (ubuntu) 側の制限をしている、

According to the Microsoft WSL page on github.com, iptables isn't supported.
https://github.com/Microsoft/WSL/issues/767

I'd note that the WSL page on github.com says that WSL now supports iptables in very recent versions, 
though it is evident some people are still having problems

Windows restrict that command in WSL without authorization from administrator.

You just have to run WSL on CMD/Powershell/Ubuntu.exe as administator, then try this command again:

sudo iptables -L -v
I tested on WSL v1, but it should also work on WSL v2.

という記事をみて、

・OSのビルドも新しい
・wsl2 で実行している、
・管理者権限実行もしている

にもかかわらずのエラーとなり、
超えられる要因、超えられない要因がありそうで、
かつ端末固有問題もありそうで、エラーの解消を断念しました

==========================================
**環境4：windows 10 home + wsl2 + ubuntu 20.04**

　**macbook pro 13-inch, early 2011
　core i7-2620M 2.7GHz 2コア/4スレッド
　16 GB ram / HDD 500GB 5,400rpm**

**・動作：まる (〇)**
**・安定性：まる (〇)**

```bash:
> winver
21H2 (os build 19044.2006)
```

```bash:
$ google-chrome --version
Google Chrome 80.0.3987.149
```

```bash:
$ pip list
chromedriver-binary 80.0.3987.106.0
selenium 3.141.0
urllib3 1.26.12
```

```python:sample1.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary

from selenium.webdriver.common.by import By

opts = Options()
opts.add_argument('--headless')
opts.add_argument('--no-sandbox')
opts.add_argument('--display-dev-shm-usage')

driver = webdriver.Chrome(options=opts)
```

-> 機種がかなり古いため、処理は遅いですが、
　windows 10 + このビルドでは、
　動作、安定性という面では、
　特にエラーもなく動作しました

==========================================

.
**---- (02) レンタルサーバー ----------------------**

　**さくらインターネット
　さくらのレンタルサーバ
　スタンダードプラン**

**・動作：ばつ (×)**
**・安定性：省略 (ー)**

　レンタルサーバーでは基本的には権限問題で
　できない認識だったのですが、以下の記事があり、
　念のため、試してみました

【さくらレンタルサーバー】Pythonのseleniumで定期実行する
https://zenn.dev/eito_blog/articles/bbc6b8510be3b2

```bash:
　% sudo vim /etc/yum.repos.d/google-chrome.repo
　-> Error /usr/local/bin/sudo: Permission denied.
```

-> やはり、推測通り、sudo 権限なし, /etc/ 配下操作も もちろん NG
　リポジトリの編集ができないため、
　Google Chrome のインストールができません　という結果でした

エックスサーバーも以下の方のように
【Python】XserverではSeleniumを使ったスクレイピングができない
https://itoraa.com/?p=1019

レンタルサーバー環境では
静的 beatifulsoup は、動作しますが、
動的 selenium は、権限問題で
実現できない可能性が高いです


.
**---- (03) Google Colaboratory (SaaS) ------------**

　**surface pro7
　core i7-1065G7 1.3GHz 4コア/8スレッド
　16 GB ram / SSD 256GB
　FireFox ver.102.0.1 64bit (Browser) -> Google Drive**

**・動作：まる (〇)**
**・安定性：三角 (△)**

※直接確認ができなかったので推測 (??? はバージョン不明)

```bash:
Google Chrome 107.0.5304.87
chromium-chromedriver ???
selenium ???
urllib3 1.24.3
```

Google Colaboratory は、標準仕様では
pip モジュールが保存できないのですが、
こちらの方がおっしゃっているとおり、
Gドライブに保存することができます

Google Colabでpip installしたものを消えないようにする
https://qiita.com/ezoalbus/items/d42d47685b592816054d

ですが、こちらで試した結果、webdriver は保存が
できなかったので、毎回インストールする形になりました
(通常の chromedriver-binary ではなく、chromium-chromedriver です)

また、Gドライブに pip やモジュールを事前に格納しておき、
毎回処理ごとにドライブマウントして、パスを通してます


```python:sample1.py
!apt-get update
!apt install chromium-chromedriver
!cp /usr/lib/chromium-browser/chromedriver /usr/bin/

from google.colab import drive
drive.mount('/content/gdrive')

package_path = '/content/gdrive/MyDrive/pip/my-site-packages/'

import sys
sys.path.append(package_path)

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

from selenium.webdriver.common.by import By

opts = webdriver.ChromeOptions()
opts.add_argument('--headless')
opts.add_argument('--no-sandbox')
opts.add_argument('--disable-dev-shm-usage')

driver = webdriver.Chrome('chromedriver',options=opts)
```

**・不安定要素**
　処理が遅いこと、および、手動実行、手動マウント認証が必要なこと、
　および、問題なく処理が完了する場合と、
　頻度はたまにといった感じですが、
　以下のエラーが発生する場合があり、
　運用にのせるにはちょっと懸念があります

**エラー1: web driver エラー (page crash)**
　Message: unknown error: session deleted because of page crash from tab crashed
　(Session info: headless chrome=107.0.5304.87)

　ヤフー天気のサンプルとは別に、
　取得後にスプレッドシートへの書き込み処理を追加してみた場合、

**エラー2: google api / spread sheet 接続エラー1 (Read timed out)**
　HTTPSConnectionPool(host='sheets.googleapis.com', port=443): Read timed out. (read timeout=120)

**エラー3: google api / spread sheet 接続エラー2 (service is currently unavailable)** 
　{'code': 503, 'message': 'The service is currently unavailable.', 'status': 'UNAVAILABLE'}


.
**---- (04) linux ネイティブ ----------------------**

==========================================
**環境1：elementary os 5.1**

　**surface pro7
　core i7-1065G7 1.3GHz 4コア/8スレッド
　16 GB ram / SSD 256GB**

**・動作：まる (〇)**
**・安定性：まる (〇)**

```bash:
$ google-chrome --version
Google Chrome 99.0.4844.84 
```

```bash:
$ pip list
chromedriver-binary 99.0.4844.51.0
selenium 4.4.3
urllib3 1.26.12
```

```python:sample1.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary

from selenium.webdriver.common.by import By

opts = Options()
opts.add_argument('--headless')
opts.add_argument('--no-sandbox')
opts.add_argument('--disable-dev-shm-usage')

driver = webdriver.Chrome(options=opts)
```

-> 特にエラーもなく安定して動作しました

==========================================
**環境2：xserver vps / ubuntu 22.04**

　**vCPU AMD EPYC(Milan) 3コア
　2GB ram / NVMe SSD 50GB**

**・動作：まる (〇)**
**・安定性：まる (〇)**

```bash:
$ google-chrome --version
Google Chrome 99.0.4844.84
```

```bash:
$ pip list
chromedriver-binary 99.0.4844.51.0
selenium 4.2.0
urllib3 1.26.5
```

```python:sample1.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary

from selenium.webdriver.common.by import By

opts = Options()
opts.add_argument('--headless')
opts.add_argument('--no-sandbox')
opts.add_argument('--disable-dev-shm-usage')

driver = webdriver.Chrome(options=opts)
```

-> 特にエラーもなく安定して動作しました

==========================================


---

### **[ 3. デザート ]**

pip の chromedriver-binary は、
Google Chrome の主となる version の対となる
version のインストールが必要です

例えば、
Google Chrome ver.90 に、
chromedriver-binary ver.91 は使えません

ちなみに、
2022/12/02 時点の最新 Google Chrome version は、
108.0.xxxx 系なのですが、

```bash:
$ pip install chromedriver-binary==200
```

など、存在しない version 指定をすると
「そんなバージョンは存在しません」と、怒られますが、
どの version が存在するのか教えてくれます

```bash:
ERROR: Could not find a version that satisfies the requirement chromedriver-binary==200

(from versions: 2.29.1, 2.31.1, 2.33.1, 2.34.0, 2.35.0, 2.35.1, 
2.36.0, 2.37.0, 2.38.0, 2.39.0, 2.40.1, 2.41.0, 2.42.0, 2.43.0, 
2.44.0, 2.45.0, 2.46.0, 70.0.3538.16.0, 70.0.3538.67.0, 
70.0.3538.97.0, 71.0.3578.30.0, 71.0.3578.33.0, 71.0.3578.80.0, 
71.0.3578.137.0, 72.0.3626.7.0, 72.0.3626.69.0, 73.0.3683.20.0, 
73.0.3683.68.0, 74.0.3729.6.0, 75.0.3770.8.0, 75.0.3770.90.0, 
75.0.3770.140.0, 76.0.3809.12.0, 76.0.3809.25.0, 76.0.3809.68.0, 
76.0.3809.126.0, 77.0.3865.10.0, 77.0.3865.40.0, 78.0.3904.11.0, 
78.0.3904.70.0, 78.0.3904.105.0, 79.0.3945.16.0, 79.0.3945.36.0, 
80.0.3987.16.0, 80.0.3987.106.0, 81.0.4044.20.0, 81.0.4044.69.0, 
81.0.4044.138.0, 83.0.4103.14.0, 83.0.4103.39.0, 84.0.4147.30.0, 
85.0.4183.38.0, 85.0.4183.83.0, 85.0.4183.87.0, 86.0.4240.22.0, 
87.0.4280.20.0, 87.0.4280.87.0, 87.0.4280.88.0, 88.0.4324.27.0, 
88.0.4324.27.1, 88.0.4324.96.0, 89.0.4389.23.0, 90.0.4430.24.0, 
91.0.4472.19.0, 91.0.4472.101.0, 92.0.4515.43.0, 92.0.4515.107.0, 
93.0.4577.15.0, 93.0.4577.63.0, 94.0.4606.41.0, 94.0.4606.61.0, 
94.0.4606.113.0, 95.0.4638.10.0, 95.0.4638.17.0, 95.0.4638.54.0, 
95.0.4638.69.0, 96.0.4664.18.0, 96.0.4664.35.0, 96.0.4664.45.0, 
97.0.4692.20.0, 97.0.4692.36.0, 97.0.4692.71.0, 98.0.4758.48.0, 
98.0.4758.80.0, 98.0.4758.102.0, 99.0.4844.17.0, 99.0.4844.35.0, 
99.0.4844.51.0, 100.0.4896.20.0, 100.0.4896.60.0, 101.0.4951.15.0, 
101.0.4951.41.0, 102.0.5005.27.0, 102.0.5005.61.0, 103.0.5060.24.0, 
103.0.5060.53.0, 103.0.5060.134.0, 103.0.5060.134.1, 104.0.5112.20.0, 
104.0.5112.29.0, 104.0.5112.79.0, 105.0.5195.19.0, 105.0.5195.52.0, 
106.0.5249.21.0, 106.0.5249.61.0, 107.0.5304.18.0, 107.0.5304.18.1, 
107.0.5304.62.0, 108.0.5359.22.0, 108.0.5359.71.0)

ERROR: No matching distribution found for chromedriver-binary==200
```

ので、指定の Google Chrome の version の
対となる version 指定ができます

```bash:
$ pip install chromedriver-binary==105.0.5195.19.0
```

本来は、chromedriver-binary は、
google chrome のメインバージョン同等かつ、
少し上のマイナーバージョンが必要なのですが、
きれいな揃え方ができなかったため、
近しいバージョンにて動作テストしてます
(なぜか下位マイナー version で動作してます)

また、chromedriver-binary は、python 上で、
import chromedriver-binary
とすると怒られます、
import chromedriver_binary
と記述します (ハイフンではなくアンダーバー)

---
.