Herokuで日本語を含むページのスクリーンショットを撮ってみた(その2)
前回、node-webshotを利用してスクリーンショットを撮っていましたが、PhantomJSが開発終了していることに気づいたため、node-webshotからPuppeteerに変更してみました。(よくよく見ると、node-webshotも2016年から更新されていないんですね…)
Puppeteerを使ってみる
いつものごとくnpm、またはyarnでPuppeteerをインストールすると利用できます。
npm i puppeteer
# または
yarn add puppeteer
それぞれの関数はPromiseで返ってくることが多いため、サンプルを見てもawaitを多用しているのが印象的でした。 取り敢えずスクリーンショットを取るには、こんな感じでOKです。
import * as puppeteer from 'puppeteer'
const url = 'http://example.com'
(async () => {
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.goto(url)
// スクリーンショットを保存
await page.screenshot({path: 'example.png'})
await browser.close()
})()
ウィンドウサイズを設定する
キャプチャするウィンドウサイズを指定する際は、setViewport
関数が用意されています。
// 省略
const width = 1024
const height = 768
(async () => {
// 省略
const page = await browser.newPage()
await page.setViewport({
width,
height
})
// 省略
})()
deviceScaleFactor
で、高解像度端末をシミュレーションすることも出来るみたいですね。
Basic認証下のページにアクセスする
Puppeteerには、authenticate
メソッドがありました。
// 省略
const userId = 'user_id'
const passWord = 'password'
(async () => {
// 省略
await page.authenticate(userId, passWord)
// 省略
})()
node-webshotと同様に、setExtraHTTPHeaders
によってheaderを追加することで対応が可能です。
(前回に引き続きCryptoJSでBase64エンコードしてます)
/* 下記の様な記述はしなくてもOK
import * as CryptoJS from 'crypto-js';
// 省略
const userId = 'user_id'
const passWord = 'password'
(async () => {
// 省略
const wordArray = CryptoJS.enc.Utf8.parse(userId + ':' + passWord)
await page.setExtraHTTPHeaders({
Authorization: 'Basic ' + CryptoJS.enc.Base64.stringify(wordArray)
})
// 省略
})()
*/
ページ全体を撮影する
ページ全体なのか、ウィンドウ範囲内だけなのかも、screenshot
のオプションで制御が可能です。
その他ちょっとしたオプションも併せてご紹介。
// 省略
(async () => {
// 省略
await page.screenshot({
path: 'example.jpg', // example.jpg に保存
type: 'jpeg', // JPEG形式で保存
quality: 80, // 品質を0-100で指定
fullPage: true // trueにするとページ全体を保存
})
// 省略
})()
また、clip
で切り抜きも出来るようですね。
Herokuで動かしてみる
次に、Herokuで動かしてみようとすると、そのままでは動かないことが分かりました。 そのまま動かそうとして発生したエラーのURLに、まさにHerokuの場合の解決方法が記載されていました。
Buildpackを追加する
(多分)初期状態では必要なライブラリが揃っていない様子なので、有志の方が作ってくれたBuildpackを追加して、Puppeteer(Chrome)が動く環境を整える、ということだと思います。
Herokuのダッシュボードからの場合は、Settings
-> Buildpacks
でGitHubのURLを入力します。
入力するURLはこちらか、日本語・中国語・韓国語に対応させたい場合はこちらです。
ちなみに、後者のBuildpackを利用する場合は、前回追加したフォントは不要なので、容量を削減する上でも削除した方が良いでしょう。
というか、無料枠の500MB超えちゃってので
もしくは、Heroku CLIをインストールしているのであれば下記コマンドでも大丈夫です。
heroku buildpacks:add https://github.com/CoffeeAndCode/puppeteer-heroku-buildpack
Puppeteerの起動オプションを追加
Buildpackを追加しただけでは、まだエラーが出てしまうので、Puppeteerの起動オプションを追加します。
import * as puppeteer from 'puppeteer'
const url = 'http://example.com'
(async () => {
// 起動オプションを追加
const browser = await puppeteer.launch({
args: [
'--enable-font-antialiasing',
'--no-sandbox',
'--disable-setuid-sandbox'
]
})
const page = await browser.newPage()
await page.goto(url)
await page.screenshot({path: 'example.png'})
await browser.close()
})()
(Herokuじゃない時と振り分けておいた方が良いかも?)
雑感
前回のnode-webshotに比べると、Heroku上での起動に少しつまづいてしまいましたが、node-webshotで気になっていた点が解消されたので、変更して良かったと思いました。
また、Puppeteerに乗り換えるちょっと前にawait、asyncを勉強していてタイムリーでした。TypeScript(JavaScript)楽しいです。