Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9229

Puppteerでキャプチャ画像を取得 part1

$
0
0

概要

エンジニアもどき2年目に入りました。色々あって以下を行うLambda関数を作成することになりました。
色々学びがあったので備忘録がわり兼アウトプットのために書くことにしました。

  1. 特定のページのキャプチャ取得
  2. 取得したキャプチャをS3に保存
  3. S3に保存したURLをDyanmoに記録

part1では1. 特定のページのキャプチャ取得の実装とデプロイまで行います。
part1での実装内容はこちら

前提

以下の内容が出てきます。インストールなどの準備は完了している前提です。

  • nodejs
  • ServerlessFramework
  • yarn
  • webpack
  • iamのユーザ作成済み

実装作業

1. 準備

フォルダとテンプレートの作成をします。

mkdir puppeteer-capture
cd puppeteer-capture
serverless create --template aws-nodejs

作成されたテンプレートは次のような構成になります。
image.png

また、webpackを使用する(modeule構文などesnextで実装する)ため次のパッケージも追加します。

yarn add -D webpack webpack-cli
yarn add -D @babel/core @babel/preset-env babel-loader
yarn add -D serverless-webpack

webpackの設定を書きます。

jsconfig.json
{"compilerOptions":{"module":"esnext","baseUrl":".",},"exclude":["node_modules"]}
webpack.config.js
constpath=require('path');constslsw=require('serverless-webpack');module.exports={mode:slsw.lib.webpack.isLocal?'development':'production',entry:slsw.lib.entries,devtool:slsw.lib.webpack.isLocal?'cheap-module-eval-source-map':'source-map',output:{libraryTarget:'commonjs',filename:'[name].js',path:path.join(__dirname,'.webpack'),},target:'node',module:{rules:[{test:/\.js$/,enforce:'pre',exclude:/node_modules/,include:__dirname,use:[{loader:'babel-loader',},],},],},};

以上で事前準備は完了です。

2. キャプチャを取得する関数の実装

キャプチャを取得してローカルに保存する関数を作成します。

2-1. ライブラリの追加

今回はブラウザを操作するpuppeteer-coreとAWS上でchromium(ブラウザ)を動かすchrome-aws-lambdaを使用します。また、ローカルでの動作確認用にpuppeteerも追加しています。

# ライブラリの追加
yarn add puppeteer-core chrome-aws-lambda
yarn add -D puppeteer

事前準備で追加したwebpackの設定を除き、package.jsonに以下の3つのライブラリが追加されていれば完了です。

package.json
{"devDependencies":{//・・・ 省略 ・・・"puppeteer":"^3.0.2",//・・・ 省略 ・・・},"dependencies":{"chrome-aws-lambda":"^2.1.1","puppeteer-core":"^3.0.2"}}

2-2. 実装

handler.jsにキャプチャの取得/ローカルへの保存を行う関数を実装します。

handler.js
import{args,defaultViewport,executablePath,headless,puppeteer}from'chrome-aws-lambda';import{writeFileSync}from'fs';constgetCapture=async(url)=>{// ブラウザの起動letbrowser=null;try{browser=awaitpuppeteer.launch({args,defaultViewport,executablePath:awaitexecutablePath,headless,});// ページに移動constpage=awaitbrowser.newPage();awaitpage.goto(url);// キャプチャの取得(フルページ、jpegを指定)returnawaitpage.screenshot({fullPage:true,type:'jpeg'});}catch(error){console.log(error);returnnull;}finally{if(browser!==null){awaitbrowser.close();}}};exportconstcaptureFunction=asyncevent=>{consturl=event.url||'https://google.com/';// キャプチャ取得constjpgBuf=awaitgetCapture(url);if(!jpgBuf){return{statusCode:500,body:'キャプチャの取得に失敗しました.'};}// ファイルに書き出しwriteFileSync('/tmp/hoge.jpg',jpgBuf);return{statusCode:200,body:'キャプチャの取得に成功しました。'};};

2-3. 動作の確認

まずはserverless.ymlを以下のように編集します。
regionやprofileの項目は各自の環境に合わせて記述してください。

serverless.yml
service:puppeteer-captureprovider:name:awsruntime:nodejs12.xregion:ap-northeast-1profile:privatestage:dev# 使用するプラグインplugins:-serverless-webpack# 関数の設定functions:captureFunction:handler:handler.captureFunction

以下を実行して動作の確認を行います。

# ローカルでの動作確認
sls invoke local--function hello -c ./serverless.yml

一瞬ブラウザが立ち上がり/tmphoge.jpgという名前でキャプチャ画像が取得できていればOKです。
任意のページのキャプチャを取得する場合は、以下のように実行します。

# 任意のページのキャプチャを取得
sls invoke local--function captureFunction --data'{"url":"https://qiita.com/"}'-c ./serverless.yml

デプロイ

作成したLambda関数をAWS上にデプロイします。

1. 準備

chrome-aws-lambda込みでlambdaにデプロイすると容量が結構大きくなってしまうためパッケージはLambda Layerに入れておき、そこから使うことにします。

まずは、Layersに配置するものを格納しておくディレクトリを作成し、パッケージを追加します。
ドキュメントによると[任意の名前]/nodejs/node_modulesにパッケージを追加する必要があるようです。

# ディレクトリの作成mkdir layers/nodejs
cd layers/nodejs
# パッケージの追加
yarn init -y
yarn add chrome-aws-lambda puppeteer-core

2. Layersの設定

Layersに格納するパッケージを格納しているパスと関数からの参照を行うための設定をserverless.ymlに記述します。
コンソールからもLayersの設定はできますが、今回は設定に関しては全てコンソールを使わずに行ないます。
Layer設定のname項目によりlambdaだけでなくlayerもstageでの切り分けができます。

serverless.yml
service:puppeteer-captureprovider:# ・・・ 省略 ・・・# 追加1 : Layer名などの環境変数environment:STAGE:${self:provider.stage}PREFIX:${self:service}-${self:provider.stage}CAPTURE_LAYER:${self:provider.environment.PREFIX}-capture-layer# ・・・ 省略 ・・・# 関数の設定functions:captureFunction:handler:handler.captureFunction# 追加2 : Layerの参照layers:-{Ref:CaptureLayerLambdaLayer}# 追加3 : Layerの設定layers:CaptureLayer:path:layersname:${self:provider.environment.CAPTURE_LAYER}

3. デプロイと動作確認

以下のコマンドでデプロイすると画像のような結果が得られます。

# デプロイ
serverless deploy       

image.png

後はデプロイした関数の動作を確認するだけです。

# デプロイした関数の実行
sls invoke --function captureFunction -c ./serverless.yml   
sls invoke --function captureFunction --data'{"url":"https://qiita.com/"}'-c ./serverless.yml

以下のようにレスポンスが返ってきていれば完了です。

image.png

lambdaは実行後、使用されたすべてのリソース(に格納されているすべてのファイルを含む)が破棄されてしまうので、/tmpではなくS3などに保存する必要があります。そこで次回は2. 取得したキャプチャをS3に保存するように修正します。

おわりに

特に大変だったのは次の3点でした。

  • ちゃんとwebpackを使う
  • ServerlessFrameworkだけで完結
    • コンソールでLayerのzip追加しなくても何とかできないか
  • Layerをstageで切り分ける

AWS Serverless Application Modelも気になるのでいずれはそちらも使ってみたいなぁ。

参考


Viewing all articles
Browse latest Browse all 9229