PlaywrightをM1 macで使う

## 前提

- macOS Ventura
- Apple Silicon M1 MAX
- Python3
- Playwright (`脚本家` という意味の英単語だそうです)

## Docker で使うのは敷居が高い？

docker-compose でコンテナを作ってその中で　`playwright codegen` を実行すると以下のエラーになって、その壁をクリアするのは容易ではないように見えるので、しっかり挫けました `orz`
headlessモードにすると実行できそうですが、まずは画面も見たいので……

```
root@1e2f1c2c1098:/# playwright codegen wikipedia.org
[Error:
╔════════════════════════════════════════════════════════════════════════════════════════════════╗
║ Looks like you launched a headed browser without having a XServer running.                     ║
║ Set either 'headless: true' or use 'xvfb-run <your-playwright-app>' before running Playwright. ║
║                                                                                                ║
║ <3 Playwright Team                                                                             ║
╚════════════════════════════════════════════════════════════════════════════════════════════════╝
=========================== logs ===========================
<launching> /ms-playwright/chromium-1045/chrome-linux/chrome --disable-field-trial-config --disable-background-networking --enable-features=NetworkService,NetworkServiceInProcess --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync,Translate --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-sync --force-color-profile=srgb --metrics-recording-only --no-first-run --enable-automation --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --no-sandbox --user-data-dir=/tmp/playwright_chromiumdev_profile-R9erE8 --remote-debugging-pipe --no-startup-window
<launched> pid=126
[pid=126][err] [126:140:0218/063844.147878:ERROR:bus.cc(399)] Failed to connect to the bus: Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory
[pid=126][err] [126:126:0218/063844.186308:ERROR:ozone_platform_x11.cc(238)] Missing X server or $DISPLAY
[pid=126][err] [126:126:0218/063844.186349:ERROR:env.cc(255)] The platform failed to initialize.  Exiting.
```
cli なら？と思ったんですが、うまく行かず。

```
% docker container run --name mycon -e DISPLAY=localhost:0 \
 -v X11-unix:/tmp/.X11-unix \
 -it mcr.microsoft.com/playwright/python:v1.30.0-focal-arm64 playwright codegen wikipedia.org

[Error:
╔════════════════════════════════════════════════════════════════════════════════════════════════╗
║ Looks like you launched a headed browser without having a XServer running.                     ║
║ Set either 'headless: true' or use 'xvfb-run <your-playwright-app>' before running Playwright. ║
║                                                                                                ║
║ <3 Playwright Team                                                                             ║
╚════════════════════════════════════════════════════════════════════════════════════════════════╝
=========================== logs ===========================
<launching> /ms-playwright/chromium-1045/chrome-linux/chrome --disable-field-trial-config --disable-background-networking --enable-features=NetworkService,NetworkServiceInProcess --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync,Translate --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-sync --force-color-profile=srgb --metrics-recording-only --no-first-run --enable-automation --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --no-sandbox --user-data-dir=/tmp/playwright_chromiumdev_profile-LJKD6Y --remote-debugging-pipe --no-startup-window
<launched> pid=110
[pid=110][err] [110:124:0219/015524.975100:ERROR:bus.cc(399)] Failed to connect to the bus: Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory
[pid=110][err] [110:110:0219/015525.004391:ERROR:ozone_platform_x11.cc(238)] Missing X server or $DISPLAY
[pid=110][err] [110:110:0219/015525.004413:ERROR:env.cc(255)] The platform failed to initialize.  Exiting.
============================================================]
```


## 仕方がないので普通にmac上で実行

なんで Docker を使いたかったかと言うと、macOS上でのpython環境でとにかく苦労したから。
venvがどうとか、pyenvがどうとか、もう考えたくないのよ！
という感じだったんですが、挫けてしまったので、仕方なくmacOS上で実行です。

久しぶりにmacOSでPython3を触ったので、色々必要でした。一応、下記に実行したコマンドを。

```
/Applications/Xcode.app/Contents/Developer/usr/bin/python3 -m pip install --upgrade pip
python3 -m pip install playwright
python3 -m pip install rich
playwright install
playwright codegen wikipedia.org -o test.py
```

`codegen` まで出来てしまえばこっちのものです（全然そんなことはないのだが）。

## playwright 再生

上記の `codegen` で生成されたファイルは、 python3 コマンドで再生できる。

```
python3 test.py
```

## playwright 記述

#### タイムアウト調整

```
page.set_default_timeout(100000)
```

長い時間がかかるものだと、タイムアウトで強制終了されてしまう。
`set_default_timeout` でミリ秒で指定する。
デフォルトは 30000(30秒) 長くする場合は記述する。上記の 100000 は 100秒。

#### headlessモード

```
browser = playwright.chromium.launch(headless=True)
```

headlessモードは、実際にブラウザを起動せずに、操作を行うモードです。
筆算に対する暗算のようなものです。
デフォルトでは `headless=False` になっているので、 `headless=True` にするとヘッドレスになります。

#### 画面サイズを変更

本当はスクリーンショットを取る画面のサイズに自動的になるようにしたいんですが。
いずれにしても、デフォルトの状態だと画面に収まらなかったので。

```
page.set_viewport_size({"width": 1280, "height": 2560})
```

#### selector が出現するまで待つ

```
# page.waitForLoadState()
# page.waitForSelector('#selector')
page.locator('#limit')
```

`waitForLoadState` はロードが終わるまで待つ、のはずが、「pageにはそんなメソッドはない！」と怒られました。
`waitForSelector` はセレクタが出現するまで待つ、のはずが、「pageにはそんなメソッドはない！」と怒られました。
参考したページによると、`waitForSelector を使うくらいなら、locator でセレクタを指定すれば、自動的にそこまで待つので、そっち使え` と書いてありました。
そんな訳で、最終的には `page.locator()` を使いました。

#### 非同期で呼び出される値を取得する

```
total = page.inner_text("#total")
```

上の方の処理が終わった後に、id=totalのところに値が入るので、それを取得する。

#### スクリーンショットを撮る

```
page.screenshot(path="./screenshot.png")
```

コマンド実行してるときは、 `qlmanage` を使うと便利ですね。

## 感想

Node.js の方がメジャーっぽくて、そっちの方が引っ掛かりがち。
（よくよく見てみたら、上の方に書いてた `waitForLoadState` も `waitForSelector` も、たぶん Node.js の方ですね。 `wait_for_load_state` と `wait_for_selector` は下記に有りますね。）

[page for Playwright Python](https://playwright.dev/python/docs/api/class-page)
[page for Playwright Node.js](https://playwright.dev/docs/api/class-page)

## Python 冷遇？

`playwright._impl._api_types.TimeoutError: Timeout 30000ms exceeded.`

って出たので、タイムアウト伸ばせないかな？
と思って下記のURLにアクセスし、

https://playwright.dev/docs/test-timeouts

Node.js になっているところを Python に切り替えると、

https://playwright.dev/python/docs/test-timeouts では
`This page is not available for Python.
We could not find what you were looking for.`
って出る。PythonではTimeoutは変更できないのか？