こんにちわ、PHPエンジニアのエンジニア婦人(@naho_osada)です。
私はPHPエンジニアとして8年~の経験があります。
これは「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で貼り付けるのであれば、ある程度制御できます。