AWS Lambda中Textract提取表单存为S3 CSV的代码问题排查
修复AWS Lambda中Textract表单提取并生成CSV到S3的问题
我帮你梳理下当前Lambda代码里的几个关键问题,以及修正后的完整实现方案:
原代码中的核心错误
- S3上传逻辑错误:
bucketName是字符串类型的桶名,不是boto3的Bucket对象,直接调用bucketName.upload_file()会抛出属性错误,因为字符串没有这个方法。 - 文件未正确刷新/关闭:直接用
open()创建文件对象却没使用上下文管理器(with语句),可能导致CSV内容还没完全写入磁盘就执行上传,生成空文件或不完整的文件。 - TRP模块导入不完整:原代码里只导入了
trp,但使用Document(response)需要明确导入Document类,否则会报错。 - 资源初始化位置不合理:把boto3的s3、textract客户端初始化放在lambda_handler内部,每次函数执行都会重新初始化,影响性能(Lambda执行环境可以复用,放在外部能减少重复初始化的开销)。
- 固定CSV文件名易冲突:直接用
'textractData.csv'作为目标文件名,当多个文件上传时会互相覆盖,应该和原文件关联生成唯一文件名。
修正后的完整Lambda代码
import boto3 import urllib.parse import os import csv from trp import Document # 明确导入TRP的Document类 # 初始化boto3资源和客户端,放在函数外复用执行环境 s3 = boto3.resource('s3') textract = boto3.client('textract') def write_csv_to_s3(bucket_name, source_file_path, target_key): """将本地临时CSV文件上传到S3""" try: s3.meta.client.upload_file(source_file_path, bucket_name, target_key) print(f"成功上传CSV文件到S3: s3://{bucket_name}/{target_key}") except Exception as e: print(f"上传CSV到S3失败: {str(e)}") raise e def lambda_handler(event, context): # 从S3事件中提取桶名和文件键 bucket_name = event['Records'][0]['s3']['bucket']['name'] document_key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8') try: # 调用Textract分析表单(键值对) response = textract.analyze_document( Document={ 'S3Object': { 'Bucket': bucket_name, 'Name': document_key } }, FeatureTypes=["FORMS"] ) # 使用TRP解析Textract响应 doc = Document(response) # 生成临时CSV文件路径 temp_csv_path = "/tmp/form_extract.csv" # 使用上下文管理器确保文件正确写入和关闭 with open(temp_csv_path, mode='w', newline='', encoding='utf-8') as csv_file: field_writer = csv.writer(csv_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) # 写入表头 field_writer.writerow(["Key", "Value"]) # 遍历表单字段写入CSV for page in doc.pages: if page.form and page.form.fields: # 先检查表单和字段是否存在,避免空引用错误 for field in page.form.fields: # 处理可能的空键/值,避免写入报错 key_text = field.key.text if field.key else "无键" value_text = field.value.text if field.value else "无值" field_writer.writerow([key_text, value_text]) # 生成目标S3键:替换原文件后缀为.csv,保留原路径 target_csv_key = os.path.splitext(document_key)[0] + '.csv' # 上传临时CSV到S3 write_csv_to_s3(bucket_name, temp_csv_path, target_csv_key) return { 'statusCode': 200, 'body': f"成功处理文件: {document_key},生成CSV: {target_csv_key}" } except Exception as e: print(f"处理文件失败: {str(e)}") return { 'statusCode': 500, 'body': f"处理错误: {str(e)}" }
关键修正点说明
- 资源初始化优化:把boto3的s3、textract客户端放在函数外部,Lambda执行环境复用的时候可以直接使用已初始化的客户端,提升执行效率。
- 正确的文件处理:用
with open(...)上下文管理器,确保文件在写入完成后自动关闭并刷新缓冲区,避免内容丢失。 - S3上传修复:使用
s3.meta.client.upload_file()方法,传入桶名、本地文件路径和目标S3键,这是正确的上传方式。 - 鲁棒性提升:增加了对
page.form和field.key/value的空值检查,避免因为Textract返回的表单字段为空而触发报错。 - 唯一文件名:根据原文件的键生成对应的CSV文件名(替换后缀),避免多个文件上传时覆盖问题。
- 完整的错误处理:增加了try-except块捕获异常,并返回明确的状态码和错误信息,方便调试。
额外注意事项
- 确保Lambda执行角色拥有AmazonTextractFullAccess和AmazonS3FullAccess(或更精细的权限,比如允许读取触发的S3桶、写入目标S3桶)。
- 确认Lambda层中包含了
trp模块(因为Lambda默认没有这个第三方模块,你需要把trp打包成层或者包含在部署包中)。
内容的提问来源于stack exchange,提问作者Greation
相关产品推荐
相关产品推荐

