LoginSignup
3

More than 3 years have passed since last update.

【メモ】AWS lambda layerでpuppeteer環境つくって、S3にスクショをアップロードするlambda関数をSAMでdeployして、ついでにAPI Gatewayで公開

Last updated at Posted at 2019-04-14

概要

  • lambdaでpuppeteerを動かす
  • chromeはlayerを利用
  • lambda functionはSAMを利用してdeploy
  • (おまけ) API gatewayで公開

前提

  • aws cliでawsにフルにアクセスできる状況になっている

コード

参考

以下の3つの記事を合体した感じです

手順

chromeとpuppeterのlayerを追加

AWS LambdaでPuppeteerを動かす この記事の Layerのアップロード までやる

SAMテンプレート作成

bucket は後述のlabmdaと同じものです。ご自分のbucketを指定してください。(なければ作りましょう!)

image.png

template.yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: screenshot2s3
Resources:
  Screenshot2S3Function:
    Type: AWS::Serverless::Function
    Properties:
      Policies:
        - S3CrudPolicy:
            BucketName: screenshot2s3
      FunctionName: screenshot2s3
      CodeUri: src
      Handler: index.handler
      MemorySize: 1600
      Runtime: nodejs8.10
      Timeout: 30
      Events:
        Get:
          Type: Api
          Properties:
            Path: /
            Method: get
      Layers:
        - "arn:aws:lambda:ap-northeast-1:あなたの:layer:myPup:1"

Events の箇所はおまけで使うAPI Gatewayでアクセスするためです。

Lambda Function追加

  • functions/pupfunc/index.js にLambda関数を書きます。
  • usage をもとに、screenshotをキャプチャするコードに書き換えました。
  • 日本語フォントが使えるように下記の記述を追加しました
await chromium.font('https://raw.githack.com/googlei18n/noto-cjk/master/NotoSansCJKhk-Regular.otf');

https://github.com/googlei18n/noto-cjkから選んで
https://raw.githack.com
image.png
に書いて chromium.font(ここ) に貼るだけ。

bucket はご自分のbucketを指定してください。

src/index.js
const chromium = require('chrome-aws-lambda');
const puppeteer = require('puppeteer-core');
const aws = require('aws-sdk');
const s3 = new aws.S3();
const bucket = 'screenshot2s3';
const crypto = require('crypto');

exports.handler = async (event, context) => {
  const query = event.queryStringParameters;
  const displaySize = {
    pc: {width: 1024, height: 1024},
    iPhoneX: {width: 375, height: 812},
    iPad: {width: 768, height: 1024}
  };
  const devise = displaySize['pc'];

  const url = query.url;
  let browser = null;
  await chromium.font('https://rawcdn.githack.com/googlei18n/noto-cjk/cf29231ab8029678af4bbc1a9480e2b296a5b2d3/NotoSansCJKhk-Regular.otf');

  try {
    browser = await puppeteer.launch({
      args: chromium.args,
      defaultViewport: chromium.defaultViewport,
      executablePath: await chromium.executablePath,
      headless: chromium.headless,
    });

    let page = await browser.newPage();

    await page.goto(url);
    page.setViewport({width: devise.width, height: devise.height})
    const screenshot = await page.screenshot();
    const filename = randomFilename(screenshot);
    let params = {Bucket: bucket, Key: filename, Body: screenshot};
    await s3.putObject(params).promise();
    const download_params = {Bucket: bucket, Key: filename, Expires: 86400};
    const download_url = s3.getSignedUrl('getObject', download_params);
    return ({
      "statusCode": 200,
      "body": JSON.stringify({download_url: download_url})
    })
  } catch (error) {
    return context.fail(error);
  } finally {
    if (browser !== null) {
      await browser.close();
    }
  }
};

const randomFilename = (data) => {
  const sha256 = crypto.createHash('sha256');
  sha256.update(data);
  return sha256.digest('hex') + '.png'
}

const query = event.queryStringParameters; の箇所は、後述のAPI gatewayでアクセスするためです。 lambdaだけであれば、 event.url でシンプルに受け取ってOK。

参考

--s3-bucket の指定はご自分のバケットつかってください。
SAMのデプロイは一度S3にアップロードが必要です。なければ、バケットはここをみてつくってきださい。コマンドライン一行ですよー。

sam package \
    --template-file template.yaml \
    --output-template-file packaged.yaml \
    --s3-bucket つくったバケット

sam deploy \
    --template-file packaged.yaml \
    --stack-name sam-app \
    --capabilities CAPABILITY_IAM

確認

Lambdaを開いて先ほど作った関数がデプロイされていて、layerが割り当てられていることを確認して下さい。

テストのデータは下記のようなデータを指定してください。 "https://xxxxxx.co.jp" は、なんでもいいです。

{
  "queryStringParameters": {
    "url": "https://xxxxxx.co.jp"
  }
}

lambdaのテスト実行して、ご自分のバケットに、xxxx.pngがアップロードされていれば成功です。例はyahooのサイトです。

image.png

以上。

おまけ

ドメインとってAPI gatewayで公開しました。

使い方

  • https://webscreenshot.work に url パラメータにスクショ撮りたいアドレスを書いて下さい。
  • リクエストヘッダーに x-api-key: 7eXZ6duNSJ754gLUt5ENX3mSXgnv3UqX7QYsB5ZF をいれてください。
  • 出力されるjsonの download_url のvalueにアクセスするとダウンロードできます。
  • APIキー毎に回数を制限しているので、エラーが発生したらそれは回数制限に達したからです。翌日アクセスお願いします。

curlでかくとこんな感じ。

curl -v https://webscreenshot.work/?url=https://yahoo.co.jp -H "x-api-key: 7eXZ6duNSJ754gLUt5ENX3mSXgnv3UqX7QYsB5ZF"

省略

* Connection #0 to host webscreenshot.work left intact
{"download_url":"https://screenshot2s3.s3.ap-northeast-1.amazonaws.com/b35d3bda10ac3714eb9b03b19e361cc8d801ddf61eb165fd7b489988276d2d06.png?AWSAccessKeyId=ASIAREY2BQFLWVZRL7GP&Expires=1555342761&Signature=3MkWy5EjqOchNCzJsj1qOvvan1w%3D&x-amz-security-token=FQoGZXIvYXdzECEaDLlrEieFh6KQaAnxIiLmAamAhWMbYrvRuLbJcQPyL7p%2BCx4CYVG%2BkLrRliDzXpxnmDepaxumy7kWPIyXLmqpAk6hbg2lbQhUDciPs4bgnrPr%2FjZm%2FsxtVvtOsnvP3nQRC%2FswlLsodcUR%2FicANlR2Po4yIUriJ6ZxIhj19AVZo5ZfaVdhNqF%2B0uUPRwqDZNucCEcxjuRBNDlLU%2FYk2WS%2BZatRq1geZJNBq%2Ffc%2FM5mcad%2F%2BGHE1c7ipEhVmF1FhIvyUR31GK%2F3dyhkS3iXut8lWKrxrVW0TmGH9xVmHrDp8821lg7P%2Bd6F%2FBKfT4TWQDqahk09ARnoKI6ozeUF"}%

手順

SAMでdeployするとすでにAPI gatewayにリソースが追加されていますので、それをベースに使います。

image.png

APIの必要性を trueにします

image.png

  • APIをProdでデプロイします

image.png

image.png

image.png

image.png

以上

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3