背景
先日テンプレを元にサイトを生成するという面倒な手仕事をAstroで片付けたのだが、それに付随して、生成したサイトのキャプチャ画像をとるというタスクもあり、こいつも何とか楽をしようと自動化ツールを選定した。
Pappeteer と PlayWright の2つが候補に上がって、両方触ってみたのでメモ。
先に結論
特にこだわりがなければ PlayWright を使っておけば良いと思う。
比較
ツールの位置付け
Pappeteerがブラウザのオートメーションツールとされているのに対して、PlayWrightはテストフレームワークとして強く売り出している感じ。
ただ、PlayWrightもテスト以外の目的てブラウザオートメーションに使えるし、PappeteerもJestなどのテストフレームワークと組み合わせることができる。
対応ブラウザ
PappeteerはChrome(Chromium)とFirefoxに対応。
PlayWrightはChromium, WebKit, Firefox, Chrome, Edgeに対応し、モバイル端末のエミュレーションもできる。
言語
Pappeteer は TypeScript と JavaScript のみ。
PlayWright は TypeScript, JavaScript, Python, .NET, Java にオフィシャルで対応。アンオフィシャルなものならば Perl や Ruby なども。
機能差分
ブラウザのオートメーションの観点では、両者ほぼほぼ同じ。Pappeteerの作者がMSに入って作ったのがPlayWrightとのことで、API仕様も大体同じ。
ネットで見かけた比較記事ではPlayWrightの方が使いやすいAPIになっているような記載も見かけたが、Pappeteerの方に一部PlayWrightの改善が取り入れられている節がある。
PlayWrightの方が便利だと感じたことの一つは Auto-wait という機能。
DOM読み込みの遅延、JS処理などで、特定のエレメントが参照できずにエラーになるということが Pappeteer では発生し、適宜スリープ処理を入れる必要があった。
PlayWright では対象エレメントが有効になるまで自動で待ってくれるので、処理を書くのが楽だし、無駄にスリープ処理を入れないおかげでスクリプト全体の速度が上がった。
Pappeteer でも locator では自動リトライをしてくれるらしいが、Pappeteer の locator は使い所が限られる。タイミングがシビアな場面では waitForSelector を使えば良いのだろうけれど、処理が遅くなる感じがするし、あまりそのようなコンテキストをスクリプトに入れたくない。
あと、PlayWright は大体の処理を locator からネストして書けるので楽。
使い方
PlayWright
公式サイトだとテストフレームワークとしての利用の案内ばかりだが、ブラウザの自動化だけならば以下でパッケージをインストール。chromium以外を使いたい場合は、playwright-firefoxまたはplaywright-webkitを指定。
$ npm install playwright playwright-chromium
以下のように使用。
import { chromium } from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.setViewportSize({width: 1200, height: 1200}); await page.goto('https://blog.ryhmrt.com/'); await page.locator('#container').screenshot({path: 'blogshot.png'}); await browser.close();
Pappeteer
以下でパッケージをインストール。
$ npm install pappeteer
以下のように使用。
import playwright from 'playwright'; const browser = await playwright.launch(); const page = await browser.newPage(); await page.setViewport({width: 1200, height: 1200}); await page.goto('https://blog.ryhmrt.com/'); await (await page.$('#container')).screenshot({path: 'blogshot.png'}); await browser.close();
コードはほとんど同じ。