ryhmrt’s blog

意識低い系プログラマの雑記

Pappeteer vs PlayWright

背景

先日テンプレを元にサイトを生成するという面倒な手仕事を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();

コードはほとんど同じ。