apple siliconでseleniumコンテナを立ち上げてスクレイピングを行う




### 経緯

スクレイピング対象のwebページが動的(javascript)に生成するページたった。
それを解決するためSeleniumの知識が必要そうだった。
実際に動かすまでに時間がかかったので備忘録として残す。

### 目的

M1 macでdocker for macで立ち上げたseleniumコンテナを立ち上げる
seleniumコンテナを使って、動的に生成されるNHKニュースサイトの一覧を取得する

### 前提

- PC: M1 Macbook pro 14インチ 2021
- OS: macOS 12.6
- 言語: python3.9.6


### Seleniumとは

Webアプリケーションをテストするためのフレームワーク
Webブラウザを自動操作することができ、動作検証することができる。


### 必要なもの

- Webブラウザ
    - Chrome,Edge,Sarariなど
- WebDriver
    - ブラウザを操作するためのAPIを公開するモジュール。ブラウザとバージョンをあわせる必要がある
- Selenium
    - WebDriverと通信し、プログラムからブラウザを操作するライブラリ


ローカルでやろうとすると、

・検証したいWebブラウザをインストール
・Webブラウザのバージョンに合わせてWebDriverをインストール

があるので面倒。
公式Dockerは WebDriver が動作するバージョンの組み合わせでインストール済みなのでDockerを使うのがおすすめ

### dockerでseleniumコンテナを構築する

公式ドキュメント によると、
https://github.com/SeleniumHQ/docker-selenium
> For experimental docker container images, which run on platforms such as the Mac M1 or Raspberry Pi, see the >community driven repository hosted at seleniumhq-community/docker-seleniarm. These images are built for three separate architectures: linux/arm64 (aarch64), linux/arm/v7 (armhf), and linux/amd64.

m1 macは seleniumhq-community/docker-seleniarm リポジトリを参考にしてと言われているので、
https://github.com/seleniumhq-community/docker-seleniarm のドキュメントを参考にする

現時点でArm用のChromeはないので、Arm用に構築されたChromiumコンテナを立ち上げる

```console
% docker run --rm -it -p 4444:4444 -p 5900:5900 -p 7900:7900 --shm-size 2g seleniarm/standalone-chromium:latest
```


### Seleniumコンテナを使ってスクレイピングを試す

NHKニュースサイトのアクセスランキングから、記事のタイトル一覧をコンソールで表示する。
アクセスするURL: https://www3.nhk.or.jp/news/ranking/access.html

```py
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

print("**NHKニュースサイトから取得開始します...**")
try:
    # Chromeのオプションを設定する
    options = webdriver.ChromeOptions()
    # 画面を描画しない
    options.add_argument('--headless')

    # Selenium Server に接続する
    driver = webdriver.Remote(
        command_executor='http://127.0.0.1:4444/wd/hub',
        options=options,
    )

    # NHK ニュースランキングにアクセス
    driver.get("https://www3.nhk.or.jp/news/ranking/access.html")

    # 定義済みの条件で待機する(最大20秒)
    WebDriverWait(driver, 20).until(
        # 指定したページ上の要素が読み込まれるまで待機
        EC.presence_of_element_located((By.TAG_NAME, "em"))
    )

    # HTMLを文字コードをUTF-8に変換してから取得
    html = driver.page_source.encode('utf-8')

    # 取得したhtmlをBeautifulSoupで解析
    soup = BeautifulSoup(html, "html.parser")

    # 記事一覧を表示している要素だけに絞る
    section = soup.find("section", class_="content--items")
    # em要素すべてを摘出する
    emlist = section.find_all("em")

    for em in emlist:
        print(em.text)

except Exception as e:
    print("**エラーが発生しました**")
    print(e)
finally:
    print("**NHKニュースサイトから取得終了します...**")
    # ブラウザを終了する
    driver.quit()
```


#### Docker Seleniumのwebブラウザ操作を表示する

5900ポートでVNCサーバに繋げられる。
Finderを開いて `command + k`

```
vnc://localhost:5900 // パスワードは secret
```

↑のコードで動かしたいなら
`options.add_argument('--headless')` をコメントアウトする。




### 参考

[Docker+Selenium ServerでWebブラウザ自動操作環境を作る](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0662)
[Docker Desktop for Apple siliconでseleniumを使う](https://qiita.com/mejiro03/items/76f7080b3ab25cbee8e4)
[10分で理解する Selenium](https://qiita.com/Chanmoro/items/9a3c86bb465c1cce738a)
[[Python]Seleniumでのwaitの方法とは？様々な待機方法を紹介します！](https://www.fenet.jp/dotnet/column/language/7851/)
[docker-selenium 使って見た](https://qiita.com/yutachaos/items/4a1da5d55a3bf0df889e)