言語(PHP他)nodejs
更新日 : 2020年9月1日
投稿日 : 2020年3月14日

headless chrome / puppeteer(nodejs)-キャプチャを取得しよう-

headless chrome / puppeteer(nodejs)-キャプチャを取得しよう-の画像

こんにちわ、PHPエンジニアのエンジニア婦人(@naho_osada)です。
私はPHPエンジニアとして7年~の経験があります。WordPressは2年半~の経験があります。その他、jQuery、HTML、CSSも使用します。
ここでは主に過去に納品した案件や自サイト運営(エンジニア婦人ノート)で遭遇したことについて書いています。

これは「headless chromeをpuppeteerを使って操作し、キャプチャを撮って保存する仕組みを作る」というその方法のお話です。

キャプチャを撮って保存する作業を自動化したい

「今まではブラウザで決まったページを開いて手動でキャプチャを撮って保存、という作業をしていたのだけれど、そろそろ数が多くてしんどくなってきたので、自動化したい」

というようなご相談がありました(と仮定)

ブラウザを開いて、ボタンを押下すると勝手にキャプチャを撮って保存してもらう機能は?とご提案して実装してみたものの、

「動作がちょっと遅い」
「ブラウザ開いてボタン押すのが面倒」
「保存先は自分のところじゃないので、サーバーに置いてあればそれでいい」

などという苦情がありまして(と仮定)

色々考えた結果、「headless chromeを使ってキャプチャ撮って保存すればいいのではないかな?」となりました。

環境の構築

puppeteerを使うには、nodejsをインストールする必要があります。
今回はCentOS 7.7 にインストールしていきます。

nodejsのインストール

まず、nodejsのyumリポジトリを追加します。
これをやらないでyum install nodejsをやってしまうとCentOS7のデフォルトのものが古いバージョン持ってくると思います。そうするとpuppeteerが動作しません。

curl -sL https://rpm.nodesource.com/setup_12.x | sudo bash -

完了後、nodejsをインストールします。

sudo yum install nodejs
node -v

Ver12.x.xならOKです。

nodejsを実行するディレクトリを作成

nodejsを実行するディレクトリを作成します。
今回は諸々の関係上、/var/www/html/nodejs-sampleとしています(実行できればどこでもいいような気がする)
作成後、そのディレクトリの中に入っておきます。今後、この中にnode_modulesを入れていきます。

cd /var/www/html
sudo mkdir nodejs-sample
sudo chown xxxx:xxxx nodejs-sample
cd nodejs-sample

package.jsonファイルを作る

node_modulesの管理をしてくれる、package.jsonを作ります。

npm init

対話形式で作っていきます。コマンド実行後、「name」など出てきます。テスト用であればなんでもいいでしょう。
entry pointは実行するファイルを書いておきます。今回はindex.jsです。
入力していくと以下のようなpackage.jsonが作成されます。

name: sample
version: 1.0.0 
description: 
entry point: index.js
test command: 
git repository: 
keywords: 
author: Lady
license:ICT

必要なモジュールを入れていく

ここから、必要なモジュールを入れていきます。

html-minifier

npm install html-minifier

puppeteer

npm install puppeteer

その他必要なもの

html-minifierとpuppeteerを導入して、puppeteerのサンプルを実行すると、エラーが出るかと思います。

Failed to lainch the browser process!
/node_modules/pupetter/.local-chronium/ …………..

ブラウザが起動できないと言われています。これらを追加します。

yum -y install libX11 libXcomposite libXcursor libXdamage libXext libXi libXtst cups-libs libXScrnSaver libXrandr alsa-lib pango atk at-spi2-atk gtk3

実行して文字化けしたときにはIPAフォントも入れます 。

yum install ipa-gothic-fonts ipa-mincho-fonts ipa-pgothic-fonts ipa-pmincho-fonts

package_lock.jsonについて

node_modulesをインストールしていると、package_locck.jsonというファイルが作られます。

これは別環境でnpm installして環境構築する際に整合性を保つために必要なんだとか…?削除してはいけません。

尚、node_modulesは一般的にgit管理はしないようですね。なぜなら重いので。package.jsonとpackage_lock.jsonがある状態でnpm installして、必要なモジュールを入れて構築するんですね。

実行サンプルソース

index.jsファイルに以下を書き込み、実行します。
このサンプルではエンジニア婦人ノートのトップページが撮れます。URLをかえれば任意のページの取得ができますね!

const puppeteer = require('puppeteer');

(async () => {
    try{
        const browser = await puppeteer.launch({
            args: [
                '--no-sandbox',
                '--disable-setuid-sandbox'],
        });
        const page = await browser.newPage();
        await page.setViewport({width: 1800, height: 2000});
        await page.goto('https://engineer-lady.com/',{waitUntil: ["load", "networkidle2"]});

        await page.screenshot({path: 'test.png', fullPage: true});
        await browser.close();
    } catch(e) {
        console.error('err' + e);
    }
})();

ブラウザを開いて、スクリーンショットを撮って保存しています。

撮影したエンジニア婦人ノートのトップページ

これで「サーバー上にキャプチャを撮って保存する」が実装できました!
定時実行に設定すれば、毎日定時にキャプチャが保存されることになりますね。自動化の完成です…!

尚、PDFの場合はこのような記述になります。

        await page.pdf({
            path: 'test.pdf',
            width: '1200px',
            printBackground: true,
            margin: {
                top: '20px',
                right: '0px',
                left: '0px',
                bottom: '50px',
            },
            landscape: true,
        });

背景色を入れたいときは「printBackground: true」を入れます(というか入れないとサイトによっては見た目が白くなって出力される)

chroniumの設定一覧

「cont browser = await puppeterr.launch({})」内のオプション(args)ですが、一覧はこちらにありました→「List of Chronium Command

備考:node_modulesが入らなかったとき

Proxyの関係でタイムアウトしてしまった!などの場合ですが、一般的にはプロキシの設定を変える、外す、レジストリを変えるなどがあります。

「npm registry proxy」と検索すると色々記事が出てきますが…それでも解決しなかった場合の裏技。Proxyサーバーがどうしても変更できないけどそこをなんとか…などのとき。

但し、nodejsが入っていることが前提です。

  • node_modulesが適切に入る環境下で全部インストールします。
  • node_modulesのあるフォルダをzip圧縮します(package.jsonとpackage_lock.jsonも一緒)
  • 入れたい環境にzipファイルを置きます。
  • zipファイルを解凍して、動作確認します。

まとめ

  • nodejs / puppeteerを使えば、ブラウザを介さず、人の手を介さず、キャプチャを保存することができます。しかも高速
  • 本当に簡単にできるので、ネット上に保存されては困るものを公開してはならないと改めて思う

「あれ、PDFがうまくいってない…?」

PDFキャプチャを当サイトで試してみた方は気付いたかもしれませんが、puppeteerでPDFをするときになぜかレスポンシブ仕様になってしまいます。

原因は追究していないのでよくわかりませんが、PDFにしたい場合はpuppeteer×pdfmakeで、

「puppeteerで保存したい部分のキャプチャを撮って、そのキャプチャをpdfmakeで貼り付ける」

方法が一番うまくいくと思います。

縦に長いサイトの場合、変なところで切れてしまうこともありますが、欲しいところだけキャプチャを撮ってpdfmakeで貼り付けるのであれば、ある程度制御できます。