LoginSignup
0
1

More than 1 year has passed since last update.

Serverless FrameworkでデプロイしたLambdaでスクレイピングする。

Posted at

目的

こちらの記事は、以下の記事の第1, 2回目となります。

Lambdaを使用して、スクレイピングします。
また、Lambda Layerを使用して、Pythonで使用するパッケージを読み込ませます。インポートするパッケージをLambda Layerから読み込んでハンドラーと切り分けることで、デプロイするLambdaの容量を減らし、大規模なLambda関数を作成可能にするとともに、デプロイするまでの時間を短縮させます。

環境

$ sw_vers
ProductName:    macOS
ProductVersion: 11.6
BuildVersion:   20G165

$ sls -v
Framework Core: 2.65.0
Plugin: 5.5.1
SDK: 4.3.0
Components: 3.17.2

$ npm -v
8.1.0

$ docker -v
Docker version 20.10.8, build 3967b7d

ディレクトリ構成

ディレクトリ構成は以下。

.
├── README.md
├── lambda
│   ├── handler.py
│   └── serverless.yml
├── layer
│   ├── requirements.txt
│   └── serverless.yml
└── package.json

ちなみに、ディレクトリ構成を他の人に共有したい時は、treeコマンドを実行すると良いことに気がつきました。-Iオプションをつけると、node_modulesとかの共有したくないディレクトリは排除してくれます。

Lambda Layerの作り方

(1). serverlessコマンドを実行し、適当なテンプレートで作成する。私はAWS - Python - Scheduled Taskを選択しました。
(2). layerディレクトリに移動し、serverless-python-requirementsをインストールする。npm i serverless-python-requirements
(3). Lambda Layerに入って欲しい、requirements.txt定義する。今回デプロイするLambdaには以下を定義しておく。

beautifulsoup4>=4.10.0
requests>=2.26.0
lxml>=4.6.4

(4). serverless.ymlを作り、以下のようにする。

service: python-requirements-layer

plugins:
  - serverless-python-requirements
provider:
  name: aws
  runtime: python3.8
  region: us-east-1

custom:
  pythonRequirements:
    dockerizePip: true
    layer: true

resources:
  Outputs:
    PythonRequirementsLambdaLayerExport:
      Value:
        Ref: PythonRequirementsLambdaLayer

ポイントとしては、2つ。
1. pythonRequirementsの箇所にdockerizePipとlayerを定義しておくこと。
2. OutputsにPythonRequirementsLambdaLayerExportを定義しておくこと。

1では、dockerでパッケージ化したファイルをLambda Layerに入れることになる。結果として、一意なパッケージとなり、どこで実行しても同じパッケージになる。
2では、デプロイするLambdaからLambda Layerを読み込むためのCloudFormationへのOutputを定義している。次の章で使用する。

(5)sls deployする。

デプロイするコード

import datetime
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
import requests
import sys
sys.path.append("lib.bs4")
from bs4 import BeautifulSoup

target_url = 'https://www.yahoo.co.jp/'

def run(event, context):
    current_time = datetime.datetime.now().time()
    name = context.function_name
    logger.info("Your cron function " + name + " ran at " + str(current_time))
    r = requests.get(target_url)
    soup = BeautifulSoup(r.text, 'lxml')
    a_tag = soup.find('a')
    logger.info(a_tag)

デプロイするserverless.yml

org: ShiroUz
app: aws-python-scheduled-cron-project
service: aws-python-scheduled-cron-project

frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  logRetentionInDays: 1
  iamRoleStatements:
  - Effect: Allow
    Action:
      - logs:CreateLogGroup
      - logs:CreateLogStream
      - logs:PutLogEvents
    Resource:
      - "*"
  lambdaHashingVersion: 20201221

custom:
  default_stage: dev
  stage: ${opt:stage, self:custom.default_stage}
  requirements_service: python-requirements-layer
  requirements_export: PythonRequirementsLambdaLayerExport
  requirements_layer: ${cf:${self:custom.requirements_service}-${self:custom.stage}.${self:custom.requirements_export}}
  prune:
    automatic: true
    number: 5

functions:
  cronHandler:
    handler: handler.run
    layers:
      - ${self:custom.requirements_layer}

上記コードのポイントは以下の3つ。
1. Lambda Layerをハンドラーで読み込む。
2. IAMロールを設定する。
3. pruneを設定する。

1について、customの中で、設定しているrequirements_layerを読み込んで、Lambda Layer化する。
2について、providerでIAMロールを定義して、ログの出力を有効化する。
3について、pruneを設定しておくことで、Lambdaの古いバージョンが残らなくなる。npm i serverless-prune-pluginでインストールする。

上記、serverless.ymlとhandler.pyを適応させた状態で、sls deployすることで、AWSにデプロイできる。

参考

以下、とっても参考にさせていただきました。ありがとうございます。
https://blog.ikedaosushi.com/entry/2019/04/07/012612

0
1
0

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
0
1