maku693です。
Github ActionsでPuppeteerを簡単に使えるCustom Actionを作りました。
最近Github Actions上でブラウザを動かしたくなったのですが、いちいち実行環境を整えるのも面倒なので、サクッとできないものかと調べたところ、意外とPuppeteerをそのまま使えるactionというのは存在しないようだったので、自分で作りました。
使い方はREADMEに書いてありますが、ここでも軽く紹介します。
以下のjobでは、ページのタイトルを取ってきて、それを後続のstepで利用しています。
- id: get-title uses: maku693/action-puppeteer-script@v0 with: script: | const page = await browser.newPage(); await page.goto("https://maku693.hatenablog.jp"); const title = await page.$eval('title', el => el.textContent); return title;- run: echo '${{ steps.get-title.outputs.result }}' # `"The Third Law"` が出力される
ちゃんと試していないのですが、基本的にほぼ全てのPuppeteerのAPIが使えると思うので、スクリーンショットを撮るとか、ファイルをダウンロード・アップロードするとか、ブラウザが必要な色々な場面の自動化に活用できると思います。
ここから先はこのActionを作るにあたっておもしろかったポイントを紹介しようと思います。
Github ActionsのJavaScript actionはNode.jsで実行されるのですが、実行前にpackage.jsonを見て依存をインストールしてくれるような仕組みは存在しないので、node_modulesを直接コミットするか、webpackなどのツールで依存ライブラリをバンドルしてリポジトリにコミットしておく必要があります。
今回はドキュメントでもおすすめされていた@vercel/nccを使ってみました。
これはwebpackをラップしたツールで、webpackそのものが主にブラウザ向けにさまざまなアセット等を含めてバンドルする仕組みを提供するのに対し、nccはよりミニマルに、あるnpmモジュールを1ファイルにバンドルすることに特化しているようです。
使い方は簡単でハマりどころもなく、ドキュメント通りにコマンドを呼び出すだけでバンドルを実行してくれて便利でした。
PuppeteerはDevTools Protocolに準拠したブラウザを操作するライブラリなので、当然ながらブラウザがどこかにインストールされていないと利用できません。
普通のNode.jsプロジェクトでPuppeteerを使う際は、npm install puppeteer
すると自動でChromiumがダウンロードされる*1ので意識する必要はないのですが、今回はGithub Actionsで実行したい都合上、自分でどうにかしてrunnerにChromiumをインストールしなければなりません。
Actionの利用者側でChromiumをインストールしてもらい、それを利用することもできなくはないのですが、かっこわるいし不便すぎると思ったので、 このAction単体で完結するようにできないか検討しました。
最初はJavaScript actionにするのをあきらめて、Docker container actionにしてコンテナの中にChromiumをインストールすることも考えたのですが、Dockerコンテナ内でChromiumを実行するのは少しトリッキーな上、Node.jsアプリケーションのDockerイメージは肥大化しがちで管理や利用が大変そうなため、JavaScript actionのまま開発を進めることにしました。
何か活用できるものはないかとPuppeteerのソースコードを眺めたところ、
仕組みで利用されているnpm install puppeteer
する際に自動でChromiumがダウンロードされるBrowserFetcher
というクラスが公開されていたので、これを利用してactionの実行時にChromiumをダウンロードすることに決めました*2。
BrowserFetcher
を使い始めたところまではよかったのですが、ダウンロードする際にブラウザのリビジョンを指定する必要がありました。npm install puppeteer
する際に実行されるスクリプトでは、決めうちでリビジョンを指定してダウンロードしていたのですが、このリビジョンはPuppeteerのAPIとしては公開されていません。したがって自分でリビジョンを決める必要がありました。
最初はChromiumの配布サイトに最新のリビジョンを示すファイルが置いてあるので、これを参照して最新のリビジョンを取るようにしていたのですが、このファイルと実際のバイナリの更新タイミングに差があるのか、ときどきダウンロードできないことがありました。
確実に存在するリビジョンを指定したいのですが、もうここまで来たらどんな雑な方法でも良いかと思い、node_modules内に存在するPuppeteerのソースコードから、自動ダウンロードに使われるリビジョン番号を抜き出し、それをソースコードとして出力するスクリプトを書いて、ビルドステップの一環として実行するようにしました。こうして無理やり抜き出したリビジョンをもとにChromiumをダウンロードするようにしました。
これでついにこのactionの実行時にChromiumをダウンロードして、Puppeteerを動かせるようになりました。
都度ダウンロードする方式だとそれに時間がかからないか気になるところですが、自分のリポジトリで試した限りでは20秒弱でダウンロードが終わっていたので、そこまで気にする必要はなさそうです。
というわけで、完成するまでには書いたこと以外にも紆余曲折あったのですが、思いついてから2日くらいで完成できました。久々に短期間で何かを完成させる体験ができて楽しめました。
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。