Puppeteerで行う画面スクリーンショット

Puppeteerの概要と用途

今回ご紹介するPuppeteer(パペティア)はheadless-Chrome(GUIがないGoogle Chrome)やChromiumを制御するAPIを提供するGoogle製ライブラリです。
ブラウザで手動実行できるほとんどのことは、Puppeteerを使用して実行できるそうですが、紹介例で使用されるのは大抵がスクリーンショットです。

今回は『WEBページの一部分をスクリーンショットしその画像を保存する』という機能を既存のlaravel環境に追加する形でご紹介します。

導入内容の概要

今回はJS/TSのランタイム環境にdenoを利用する為、puppeteerからフォークされたdeno-puppeteerを利用します。
※denoはJSやTSのランタイム環境でNodeの後継のような存在です

今回はdockerで利用する為、deno-puppeteerから取得したDockerfileを利用してdenoコンテナを作り、Web APIとして実行できる形にしていきます。

構成

既存の構成にdenoコンテナ追加する形で進めます。
※要点のみを抜粋

 ┏ docker-compose.yml //(既存)  
 ┣ php //(既存)  
 ┣ deno //(新規作成)  
 ┃ ┗ Dockerfile //※deno-puppeteerからgit clone  
 ┣ puppeteer //(新規作成)  
 ┃  ┣ app
 ┃  ┃ ┣ router.ts    
 ┃  ┃ ┣ server.ts   
 ┃  ┃ ┗ Controllers   
 ┃  ┃   ┗ controller.ts     
 ┃  ┗ puppeteer
 ┃    ┣ screenshot.js   
 ┃    ┗ screenshots
 ┣ laravel //(既存)  
 ┃  ┗ app  
 ┃    ┣ Console  
 ┃    ┃ ┗ Command  
 ┃    ┃   ┗ GetScreenshot.php
 ┃    ┗ Libraries  
 ┃      ┗ Screenshot.php
 ┗ その他 //(既存/省略)  

実装してみる

WEBサーバとスクリーンショット処理の準備

※要点のみを抜粋
※セキュリティ面等を考慮していない為、ご注意ください

deno側

  • 8888ポートでリクエストを受け付ける
//puppeteer/app/server.ts
await app.listen({ port: 8888 });
  • ルーティングでエンドポイントを作成
  • スクリーンショットを行いたいページのIDを引数として取るので:page_idとしておく
//puppeteer/app/router.ts
const router = new Router();
router.get('/api/screenshot/create/:page_id', controller.screenshot);
  • スクリーンショット処理の関数を作成
//puppeteer/app/controllers/Controller.ts
async screenshot(ctx: RouterContext) {
  const { page_id } = helpers.getQuery(ctx, { mergeParams: true });
  const p = Deno.run({
    cmd: ["deno", "run", "-A", "--no-check", "--unstable", "/root/puppeteer/screenshot.js", page_id]
  });
  p.close();
}
  • スクリーンショット処理を作成
  • スクリーンショットを取得したいHTML要素をidで指定(#target_ele)
//puppeteer/puppeteer/screenshot.js
// スクリーンショットするURLを指定
await page.goto(
  `http://example.com/page/${Deno.args[0]}`
);
// スクリーンショットするHTML要素、スクリーンショットサイズ、スクリーンショット位置を指定
const dimensions = await page.evaluate(() => {
  const dom_selector = "#target_ele";
  const el = document.querySelector(dom_selector);
  return {
    width: el.clientWidth,
    height: el.clientHeight,
    deviceScaleFactor: window.devicePixelRatio,
    x: 20,
    y: 232,
  };
});
// 実行
await page.screenshot({
  path: `/public/images/screenshots/${Deno.args[0]}.png`,
  clip: dimensions,
});
await browser.close();

PHP(laravel)側

  • laravel側から実行できる形を作成
  • コンテナ間通信はコンテナ名で接続できる為、URLではなくコンテナ名(deno)を指定してcurlする
//laravel/app/Libraries/Screenshot.php
public function takeScreenshot ($page_id){
  exec("curl deno:8888/api/screenshot/create/".$page_id);
}

denoコンテナ立ち上げ
(PuppeteerとChromeのインストール含)

  • container_nameをdenoに設定する
  • 頻繁に変更するファイルはvolumesでマウントしておく(imageに含めるとソースを更新する毎にbuildが必要になる為)
#docker-compose.yml
deno:
  container_name: deno
  build:
      context: ./deno
  ports:
    8888:8888
  volumes:
    ./puppeteer/app:/root/app
    ./puppeteer/puppeteer/screenshot.js:/root/puppeteer/screenshot.js
    ./laravel/public/images/screenshots:/var/www/laravel/public/images/screenshots
  • deno-puppeteerから取得したDockerfileの84行目以降を以下に変更。
#Dockerfile
# denoにパスを通す
ENV DENO_INSTALL="/root/.deno"
ENV PATH="$DENO_INSTALL/bin:$PATH"
# PuppeteerとChromeをインストール
RUN PUPPETEER_PRODUCT=chrome deno run -A --unstable install.ts
# WEBサーバーを起動
ENTRYPOINT ["deno"]
CMD ["run", "-A", "--no-check", "--unstable", "./app/server.ts"]
  • コンテナをバックグラウンドで立ち上げ
docker-compose up -d

実行

  • laravelのartisanコマンドを使用して実行
  • http://example.com/page/1から指定した座標、サイズのスクリーンショットを取得
// laravel/app/Console/Commands/GetScreenshot.php
class GetScreenshot extends Command{
  protected $signature = 'screenshot:take';
  // スクリーンショット作成
  public function handle(){
    $page_id = 1; //ページIDを取得
    $screenshot = new Screenshot;
    $screenshot->takeScreenshot($page_id);
  }
}
php artisan screenshot:take

まとめ

以上がPuppeteerで行う画面スクリーンショットのご紹介となります。
Dockerを利用する事で環境の作成・破棄が容易なのも嬉しいですね。
興味のある方は是非触ってみてください。

\ ログインしなくても検討機能が使える♪ /
Dockerの案件を見てみる



【お知らせ】
現在、エンジニアルートではフリーエンジニアを中心とした、フリーランスの お仕事紹介、お悩み相談を承っております。

一対一のカウンセリングに基づき、スキルやキャリアプランなどのご要望をお伺いしピッタリの案件をご提案します。ご参画中のご相談・節税対策、適正な給与なのか知りたい、マージンを下げたいなど何でもサポートをいたします。

案件獲得までには早ければ1〜3日、平均的に2週間以内には複数案件から選べる状況になっています。将来的な独立の相談のみでも承っております。お気軽な気持ちでご登録ください。
フリーランスを考えてる方やお仕事をご要望、面接指導などをご希望の方は、下記バナーより新規登録をお待ちしております。非公開求人多数です。

よく読まれている記事

「技術について開発言語-ツール情報」でよく読まれている記事