6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Python】S3にアップロードされたCSVファイルをAWS LambdaでJSONファイルに変換する

Last updated at Posted at 2021-01-19

本記事で目指す構成

lamda-csv-to-json.png

S3にCSVファイルをアップロード → Lambda起動 → JSONファイルに変換

使用技術

言語: Python 3.8
AWS: S3、Lambda

下準備

まず最初にIAMユーザーやIAMロール、S3バケットなどの準備を行います。

IAMユーザーを作成

今回はAWS CLIを使って作業していくので、専用のIAMユーザーを作成します。

スクリーンショット 2021-01-19 19.22.58.png

「IAM」→「ユーザー」→「ユーザーを追加」

ユーザー名: 任意
アクセスの種類: 「プログラムによるアクセス」にチェック

スクリーンショット 2021-01-19 19.28.13.png

今回はS3バケットの作成、ファイルのアップロードや削除などS3に関する基本的な動作を行いたいので「AmazonS3FullAccess」ポリシーをアタッチしておきます。

スクリーンショット 2021-01-19 19.30.55_censored.jpg

作成完了すると

  • アクセスキーID
  • シークレットアクセスキー

の2つが発行されるのでメモに控えておきましょう。

$ aws configure --profile s3-lambda

AWS Access Key ID [None]: ***************** # 自分のアクセスキーIDを入力
AWS Secret Access Key [None]: ************************** # 自分のシークレットアクセスキーを入力
Default region name [None]: ap-northeast-1
Default output format [None]: json

ターミナルで上記コマンドを打つと対話形式で情報を聞かれるので、指示に従いながら入力していきます。

S3バケットを作成

先ほど設定したAWS CLIを使ってちゃちゃっと作成してしまいます。

$ aws --profile s3-lambda s3 mb s3://test-bucket-for-converting-csv-to-json-with-lambda

make_bucket: test-bucket-for-converting-csv-to-json-with-lambda

バケット名は全世界においてユニークでないといけないので、各自オリジナルのものを考えてください。

テスト用CSVファイルを作成して試しにアップロードしてみる

$ mkdir ./workspace/
$ cat > ./workspace/test.csv << EOF
heredoc> Name,Age,Country
heredoc> Taro,20,Japan
heredoc> EOF
$ aws --profile s3-lambda s3 sync ./workspace s3://test-bucket-for-converting-csv-to-json-with-lambda

upload: ./test.csv to s3://test-bucket-for-converting-csv-to-json-with-lambda/test.csv

スクリーンショット 2021-01-19 20.04.25.png

ちゃんとバケット内に入っていれば成功。

$ aws --profile s3-lambda s3 rm s3://test-bucket-for-converting-csv-to-json-with-lambda/test.csv

動作確認が済んだので消しておきます。

IAMロールを作成

Lambdaに割り当てる用のIAMロールを作成します。

スクリーンショット 2021-01-19 19.05.42.png

「IAM」→「ロール」→「ロールの作成」

  • AmazonS3FullAccess
  • AWSLambdaBasicExecutionRole

今回は上記2つのポリシーがあればOK。

スクリーンショット 2021-01-19 19.10.42.png

適当に名前や説明文を入力して作成してください。

実装

下準備が終わったのでいよいよここから実装を行っていきます。

Lambda関数を作成

スクリーンショット 2021-01-19 20.12.45.png

「Lambda」→「関数の作成」

  • オプション: 一から作成
  • 関数名: 任意
  • ランタイム: Python 3.8
  • 実行ロール: 既存のロール(先ほど作した「s3-lambda」)
  • その他: デフォルトでOK

トリガーを作成

スクリーンショット 2021-01-19 20.19.09.png

どんなイベントが発生した際にLambdaを起動させるのかを決めるために、「Configuration」→「トリガーを追加」へ進んでください。

スクリーンショット 2021-01-19 20.22.04.png

必要事項を記入していきます。

  • トリガー: S3
  • バケット: 先ほど作成したバケット名
  • イベントタイプ: すべてのオブジェクト作成イベント
  • プレフィックス: input/
  • サフィックス: .csv

今回は「input」というフォルダ配下に「.csv」ファイルがアップロードされた事を検知した後、Lambdaを起動させる事を想定しています。

コード

import json
import csv
import boto3
import os
from datetime import datetime, timezone, timedelta

s3 = boto3.client('s3')

def lambda_handler(event, context):
    
    json_data = []
    
    # TZを日本に変更
    JST = timezone(timedelta(hours=+9), 'JST')
    timestamp = datetime.now(JST).strftime('%Y%m%d%H%M%S')
    
    # 一時的な読み書き用ファイル(後で消す)
    tmp_csv = '/tmp/test_{ts}.csv'.format(ts=timestamp)
    tmp_json = '/tmp/test_{ts}.json'.format(ts=timestamp)
    
    # 最終的な出力ファイル
    outputted_json = 'output/test_{ts}.json'.format(ts=timestamp)

    for record in event['Records']:
        bucket_name = record['s3']['bucket']['name']
        key_name = record['s3']['object']['key']
    
    s3_object = s3.get_object(Bucket=bucket_name, Key=key_name)
    data = s3_object['Body'].read()
    contents = data.decode('utf-8')
    
    try:
        with open(tmp_csv, 'a') as csv_data:
            csv_data.write(contents)
        
        with open(tmp_csv) as csv_data:
            csv_reader = csv.DictReader(csv_data)
            for csv_row in csv_reader:
                json_data.append(csv_row)
                
        with open(tmp_json, 'w') as json_file:
            json_file.write(json.dumps(json_data))
        
        with open(tmp_json, 'r') as json_file_contents:
            response = s3.put_object(Bucket=bucket_name, Key=outputted_json, Body=json_file_contents.read())
    
        os.remove(tmp_csv)
        os.remove(tmp_json)
    
    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e

これでS3バケット名「test-bucket-for-converting-csv-to-json-with-lambda/input/」にCSVファイルがアップロードされると「test-bucket-for-converting-csv-to-json-with-lambda/output/」にJSON形式に変換されたファイルが吐き出されるようになります。

$ aws --profile s3-lambda s3 sync ./workspace s3://test-bucket-for-converting-csv-to-json-with-lambda/input

upload: ./test.csv to s3://test-bucket-for-converting-csv-to-json-with-lambda/input/test.csv

再度、AWS CLIでファイルをアップロードしてみましょう。

スクリーンショット 2021-01-19 20.39.29.png
スクリーンショット 2021-01-19 20.39.59.png

バケットを確認すると「output」というフォルダが新たに作成され、中にJSONファイルが入っているはず。

[
    {
        "Name": "Taro",
        "Age": "20",
        "Country": "Japan"
    }
]

中身を確認し、しっかりとJSON形式に変換されていれば完了です。

あとがき

お疲れ様でした。今回はCSV→JSONへの変換でしたが、同じ要領で他のパターンも色々実現できると思います。

少しでも参考になれば幸いです。

参照記事

Convert CSV to JSON files with AWS Lambda and S3 Events

6
3
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
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?