Lambda FunctionでExcelファイルからCSVファイルを作成してみた

分析データがExcelで管理されていることを想定し、Lambda FunctionでCSV化
2020.08.24

データ分析におけるデータソースは、DB以外にもテキストファイルの構造化データを利用することが多くあります。

仮にデータがExcelファイルで管理されている場合、多くの場合でファイルフォーマットの変換が必要になると思います。 *1まずは、データ生成元でCSVファイルを作成すればいいと思いますが、仮にAWS側でExcelファイルをCSVファイルにする場合..というのが本エントリです。

ということで、今回はLambda Functionにて、ExcelファイルからCSVファイルを作成してみたいと思います。Lambda Function以外にも検討できるサービスはありますし、Lambda Functionの実行時間は最長15分という点についてはご留意ください。

ここでは、Lambda FunctionはS3トリガーでの起動を想定しています。以下のようなイメージです。

00

今回のやってみた環境は、SAMテンプレートにして本エントリの最後にはっておきました。

やってみた

PythonでExcelを扱うために、ここではopenpyxlライブラリを利用します。openpyxlはPythonの標準ライブラリには含まれていないので個別に取得します。また、Lambda Functionで外部ライブラリが呼び出しできるよう、ここではLambda Layerにて取り込みを行います。

openpyxlダウンロード

以下のコマンドでインストールディレクトリを指定して、パッケージのダウンロード、アーカイブします。

$ mkdir python
$ pip install -t ./python openpyxl
$ zip -r openpyxl.zip python

Lambda Layer作成

ここではAWS CLIにてLambda Layerを作成します。

$ aws lambda publish-layer-version \
    --layer-name xls-to-csv \
    --zip-file fileb://openpyxl.zip \
    --compatible-runtimes python3.6 python3.7 python3.8

Lambda Layerが作成できました。

Lambda Function作成

Lambda Functionのコードは以下となります。

import os
import boto3
import openpyxl
import csv

s3 = boto3.resource('s3')
s3_client = boto3.client('s3')

def lambda_handler(event, context):
    data_target_bucket = os.environ['DATA_TARGET_BUCKET']            # 環境変数より変換後データ保存先バケット取得
    data_source_bucket = event['Records'][0]['s3']['bucket']['name'] # Lambda関数呼び出し元バケット名
    data_source_key = event['Records'][0]['s3']['object']['key']     # オブジェクトキー取得

    # カレントディレクトリ移動
    os.chdir('/tmp')

    # S3にPUTされたExcelファイルダウンロード
    source_bucket_obj = s3.Bucket(data_source_bucket)
    source_bucket_obj.download_file(data_source_key, data_source_key)

    # Excel Book/Worksheetオープン
    wb = openpyxl.load_workbook(data_source_key)
    ws = wb.worksheets[0]

    # CSVファイル名
    csv_filename = os.path.splitext(os.path.basename(data_source_key))[0] + '.csv'

    # CSVファイル作成
    with open(csv_filename, 'w', newline="") as csvfile:
        writer = csv.writer(csvfile)
        for row in ws.rows:
            # Excel行データを取得(リスト形式)
            row_data = [cell.value for cell in row]
            # CSV書き込み
            writer.writerow(row_data)

    # CSVファイルアップロード
    s3_client.upload_file(csv_filename, data_target_bucket, csv_filename)

    return None

シンプルにExcel行データをCSVファイルに書き込むようなつくりです。Excelワークブックのシート数の考慮や、データ保存先となるS3の構成などは要件にあわせ変更ください。(ハイライト部)

Lambda Functionでは環境変数DATA_TARGET_BUCKETにて、CSVファイル格納先となるS3バケット(例:test-target-data-bucket)を指定します。指定したS3にもアクセス可能な権限(ロール/ポリシー)をLambda Functionに付与してください。

S3アップロード

今回はこちらのExcelファイルを利用して、ExcelファイルからCSVファイルを作成したいと思います。

Excelファイル内容

ExcelファイルをS3にアップします。Excel、CSVファイル格納バケットを環境変数に設定し、CSVファイル格納先は、Lambda Function実行(S3トリガー発生)前後で、宛先バケットをリストしています。

# CSV格納先S3バケット
$ S3_TARGET_BUCKET=s3://<バケット名>
# Excel格納先S3バケット
$ S3_SOURCE_BUCKET=s3://<バケット名>
$ aws s3 ls ${S3_TARGET_BUCKET}
$ ls -l b2015_gom1j_53.xlsx
$ aws s3 cp b2015_gom1j_53.xlsx ${S3_BUCKET}
$ aws s3 ls ${S3_SOURCE_BUCKET}
$ aws s3 ls ${S3_TARGET_BUCKET}
2020-08-24 11:40:12      22806 b2015_gom1j_53.csv

上記の通り、CSVファイルの作成が確認できました。作成されたCSVファイルの内容は以下です。

CSVファイル内容

さいごに

ExcelファイルからCSVファイルの作成はできました。ただし、これだけで分析の前処理が完成しているとは言えませんので、要件にあわあせて調整が必要になると思います。Lambda FunctionでExcelファイルからCSVファイルを作成するなら..といった感じで参考にしていただければ幸いです。

今回のやってみた環境のSAMテンプレートは以下になります。SAM自体の使い方についてはこちらを参考にしてみてください。

脚注

  1. Amazon QuickSightだけ利用できればいいといった要件なら、Excelファイルのままでも扱えると思いますが、AWS Glueなどを使って、RDSなどに格納しておきたいといった要件には、ファイルフォーマットの変換が必要になってきます。