0
0

AWS Textractを使用したS3アップロードトリガーの自動テキスト抽出

Posted at

この記事では、AWS SAMを使用してS3バケットにファイルがアップロードされた際に自動的にAWS Textractを利用してテキストを抽出するLambda関数を作成する方法を説明します。
このテンプレートは以下のリソースを作成します。

S3バケット: ファイルのアップロードをトリガーするための入力バケットです。
バケット名は{AccountId}-{Region}-input-bucketという形式で生成されます。

Lambda関数: S3バケットにファイルがアップロードされるとトリガーされる関数です。
この関数はPython 3.11で動作し、Textractを使用してアップロードされたファイルからテキストを抽出します。

IAMロール: Lambda関数が適切な権限を持つためのロールです。
このロールには、Lambdaの基本実行権限、S3へのフルアクセス権限、Textractへのフルアクセス権限が含まれます。

このテンプレートの構成と実装方法を解説し、最後に、実際に動作確認を行い、S3バケットにファイルをアップロードしてTextractによるテキスト抽出が成功することを確認します。

AWS SAM をインストール

> pip install aws-sam-cli 

SAM プロジェクトの作成

> sam init
Which template source would you like to use?
        1 - AWS Quick Start Templates

Choose an AWS Quick Start application template
        1 - Hello World Example

Use the most popular runtime and package type? (Python and zip) [y/N]: y

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: N

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: N  

Would you like to set Structured Logging in JSON format on your Lambda functions?  [y/N]: N

Project name [sam-app]: 好きなプロジェクト名

Lambda関数のコードを修正

S3バケットにアップロードしたファイルを textract.detect_document_text に渡して結果を extracted フォルダ内に出力します。

hello_world/app.py
# S3にファイルがアップロードされたのを検知してTextractを実行する
import boto3
import json


def lambda_handler(event, context):
    s3 = boto3.client("s3")
    textract = boto3.client("textract")

    for record in event["Records"]:
        bucket = record["s3"]["bucket"]["name"]
        key = record["s3"]["object"]["key"]

        print(f"record: {record}")
        print(f"bucket: {bucket}")
        print(f"key: {key}")

        if "/" not in key:
            response = textract.detect_document_text(
                Document={"S3Object": {"Bucket": bucket, "Name": key}}
            )

            textracted_text = ""
            for item in response["Blocks"]:
                if item["BlockType"] == "LINE":
                    textracted_text += item["Text"] + "\n"

            output_key = f"extracted/{key.split('/')[-1]}.txt"
            print(f"output_key: {output_key}")
            s3.put_object(Bucket=bucket, Key=output_key, Body=textracted_text)

template.yamlファイル修正
Role: !GetAtt LambdaExecutionRole.Arn で S3 と Textract の権限を Lambdaに設定します。

template.yaml
# S3にファイルがアップロードされたのを検知してLambdaからTextractを実行する
AWSTemplateFormatVersion: '2010-09-09'  # テンプレートのバージョンを指定
Transform: 'AWS::Serverless-2016-10-31'  # AWS SAM を使用するための変換ルール
Description:  'S3 upload trigger for AWS Textract text extraction' # テンプレートの説明文を指定

Resources:
  MyBucket:
    Type: 'AWS::S3::Bucket'  # S3 バケットのリソースタイプを指定
    Properties:
      BucketName: !Sub '${AWS::AccountId}-${AWS::Region}-input-bucket'  # バケット名を指定

  S3EventProcessorFunction:
    Type: 'AWS::Serverless::Function'  # サーバーレスの Lambda 関数を指定
    Properties:
      Handler: app.lambda_handler  # Lambda 関数のハンドラ名を指定
      Runtime: python3.11  # Lambda 関数の実行ランタイムを指定
      Role: !GetAtt LambdaExecutionRole.Arn  # Lambda 関数の実行ロールを参照
      CodeUri: hello_world/  # Lambda 関数のコードが配置されているディレクトリを指定
      Timeout: 30  # Lambda 関数のタイムアウトを指定
      Events:
        S3Event:
          Type: S3  # S3 イベントトリガーを指定
          Properties:
            Bucket: !Ref MyBucket  # トリガーする S3 バケットを参照
            Events: s3:ObjectCreated:*  # オブジェクトが作成されたときにトリガーするイベントを指定

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - arn:aws:iam::aws:policy/AmazonTextractFullAccess

ビルド実行

ターミナル
> sam build

以下のファイルができればOK
image.png

デプロイ実行

デプロイの注意点として、Textract は日本のリージョンには対応していない為、今回はバージニア北部リージョンを選択して実行しています。

ターミナル
> sam deploy --guided
...
AWS Region [us-east-1]: us-east-1
...

S3へファイルのアップロード

問題なくデプロイが完了したらS3へファイルをアップロードして動作確認を行います。
日本語はうまく変換できない為、今回はコードのスクリーンショットを使います。
test.png

バケットが2つできていると思いますが、[us-east-1-input-bucket] とついている方にアップロードしてください。
image.png

少し待ってからオブジェクトの更新を行ってください。
extracted/ フォルダが自動で作成されます。
image.png

中にテキストファイルが作成されているので、ダウンロードして開いてみます。

import boto3
import json
Codeium: Refactor | Explain I Generate Docstring IX
def lambda_handler (event, context):
s3 = boto3.client("s3")
textract = boto3.client("textract")
-
for record in event["Records"]:
bucket = record["s3"]["bucket"]["name"]
key = record["s3"]["object"]["key"]
'
response = textract.detect_document_text(
I
Document={"S30bject": {"Bucket": bucket, "Name": key}}
textracted_text="
for item in response["Blocks"]
ifitem["BlockType"] == "LINE":
|
textracted_text +=item["Text"] + "\n"
output_key = f"extracted/{key.split('/")[-1]}.txt"
s3.put_object(Bucket=bucket,Key=output_key,Body=textracted_text)

一部縦線等が変換されてしまいましたが、ほぼ同じ内容が出力されました。

ログの確認

最後にCloudWatchでログの確認を行います。
ロググループの中に/aws/lambda/~が作成されているので中を確認すると、先ほどダウンロードしたファイル名が確認できました。
image.png
エラーが出た場合も同様にログを確認してください。
※ログが出力されていない場合は、S3のputイベントに対しLambdaが動作していないので、template.yaml の設定を確認してください。

まとめ

以前の記事で紹介したS3へのアップロードイベントに対してLambda関数を実行させる方法は、非常に便利であると改めて感じました。
Lambda関数やtemplate.yamlの一部を変更するだけで、さまざまな処理を柔軟に実行できることは大きな利点で、多くのユースケースに簡単に対応できると思います。

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