Herokuで日本語を含むページのスクリーンショットを撮ってみた(その2)

前回、node-webshotを利用してスクリーンショットを撮っていましたが、PhantomJSが開発終了していることに気づいたため、node-webshotからPuppeteerに変更してみました。(よくよく見ると、node-webshotも2016年から更新されていないんですね…)

Puppeteerを使ってみる

いつものごとくnpm、またはyarnでPuppeteerをインストールすると利用できます。

1
2
3
npm i puppeteer
# または
yarn add puppeteer

それぞれの関数はPromiseで返ってくることが多いため、サンプルを見てもawaitを多用しているのが印象的でした。
取り敢えずスクリーンショットを取るには、こんな感じでOKです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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関数が用意されています。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 省略
const width = 1024
const height = 768

(async () => {
// 省略
const page = await browser.newPage()
await page.setViewport({
width,
height
})
// 省略
})()

deviceScaleFactorで、高解像度端末をシミュレーションすることも出来るみたいですね。

Basic認証下のページにアクセスする

Puppeteerには、authenticateメソッドがありました。

1
2
3
4
5
6
7
8
9
// 省略
const userId = 'user_id'
const passWord = 'password'

(async () => {
// 省略
await page.authenticate(userId, passWord)
// 省略
})()

node-webshotと同様に、setExtraHTTPHeadersによってheaderを追加することで対応が可能です。
(前回に引き続きCryptoJSでBase64エンコードしてます)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 下記の様な記述はしなくても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のオプションで制御が可能です。
その他ちょっとしたオプションも併せてご紹介。

1
2
3
4
5
6
7
8
9
10
11
// 省略
(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をインストールしているのであれば下記コマンドでも大丈夫です。

1
heroku buildpacks:add https://github.com/CoffeeAndCode/puppeteer-heroku-buildpack

Puppeteerの起動オプションを追加

Buildpackを追加しただけでは、まだエラーが出てしまうので、Puppeteerの起動オプションを追加します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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)楽しいです。

Author: SUSH
Link: http://blog.sus-happy.net/heroku-puppeteer/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.