如何用Boto3批量上传带名称图片至Amazon S3及相关问题
我来帮你梳理这两个问题的具体解决办法,结合你已有的boto3代码来优化:
1. 从本地site/uploads路径读取图片并填充images列表
你当前的images列表是硬编码的文件名和名称,要从本地指定目录读取的话,分两种场景处理:
场景一:手动关联图片与元数据(适合固定少量文件)
如果还是需要手动对应每个图片的FullName,只需要修正文件路径的拼接方式,确保能正确找到site/uploads下的文件:
import boto3 import os # 定义本地上传目录的路径 LOCAL_UPLOAD_DIR = "site/uploads" # 保持你的图片与名称映射,后续打开文件时拼接路径 images = [ ('image01.jpeg', 'Albert Einstein'), ('image02.jpeg', 'Candy'), ('image03.jpeg', 'Armstrong'), ('image04.jpeg', 'Ram'), ('image05.jpeg', 'Peter'), ('image06.jpeg', 'Shashank') ] s3 = boto3.resource('s3') for image in images: filename, full_name = image # 用os.path.join拼接路径,适配不同系统的路径分隔符 local_file_path = os.path.join(LOCAL_UPLOAD_DIR, filename) # 用with语句打开文件,自动关闭更安全 with open(local_file_path, 'rb') as file: s3_obj = s3.Object('rekognition-pictures', f'index/{filename}') ret = s3_obj.put(Body=file, Metadata={'FullName': full_name})
场景二:自动遍历目录(适合文件较多或需要动态更新)
如果你的图片和元数据有对应规则(比如配套一个JSON/CSV文件存储映射),可以自动遍历目录,不用手动维护images列表:
比如在site/uploads下新建一个image_metadata.json文件,内容如下:
{ "image01.jpeg": "Albert Einstein", "image02.jpeg": "Candy", "image03.jpeg": "Armstrong" }
然后代码可以写成:
import boto3 import os import json LOCAL_UPLOAD_DIR = "site/uploads" METADATA_PATH = os.path.join(LOCAL_UPLOAD_DIR, "image_metadata.json") # 加载元数据映射 with open(METADATA_PATH, 'r') as f: image_metadata = json.load(f) s3 = boto3.resource('s3') # 遍历目录下的所有文件,过滤图片格式 for filename in os.listdir(LOCAL_UPLOAD_DIR): if filename.lower().endswith(('.jpeg', '.jpg', '.png')): if filename in image_metadata: full_name = image_metadata[filename] local_file_path = os.path.join(LOCAL_UPLOAD_DIR, filename) with open(local_file_path, 'rb') as file: s3_obj = s3.Object('rekognition-pictures', f'index/{filename}') ret = s3_obj.put(Body=file, Metadata={'FullName': full_name})
2. 从S3获取图片并展示在网站页面上
根据你的S3桶权限设置,有两种常用的展示方式:
方式一:公开URL(适合允许公开访问的图片)
首先要确保你的S3桶或目标对象允许公开读取,可以在上传时直接设置ACL='public-read':
# 上传时添加ACL参数 ret = s3_obj.put( Body=file, Metadata={'FullName': full_name}, ACL='public-read' )
上传完成后,每个图片的公开URL格式为:https://<你的桶名>.s3.<你的区域>.amazonaws.com/<对象键>
比如你的桶是rekognition-pictures,对象键是index/image01.jpeg,区域为us-east-1,那么URL就是:https://rekognition-pictures.s3.us-east-1.amazonaws.com/index/image01.jpeg
在网站页面里,直接用这个URL作为<img>标签的src即可:
<img src="https://rekognition-pictures.s3.us-east-1.amazonaws.com/index/image01.jpeg" alt="Albert Einstein">
方式二:预签名URL(适合私有桶的权限控制)
如果你的S3桶是私有的,不想公开访问,可以生成预签名URL,这个URL有有效期(比如1小时),过期后无法访问,适合需要权限验证的场景。
后端生成预签名URL的代码:
import boto3 s3_client = boto3.client('s3') def generate_presigned_url(bucket_name, object_key, expires_in=3600): # expires_in为URL有效期,单位秒,默认1小时 return s3_client.generate_presigned_url( 'get_object', Params={'Bucket': bucket_name, 'Key': object_key}, ExpiresIn=expires_in ) # 调用示例:获取image01.jpeg的预签名URL image_url = generate_presigned_url('rekognition-pictures', 'index/image01.jpeg')
把这个URL传递给前端后,同样用<img>标签展示:
<!-- 这里用模板引擎语法示例,比如Flask的Jinja2 --> <img src="{{ image_url }}" alt="Albert Einstein">
如果需要批量展示所有图片,可以先列出S3桶中index/前缀下的所有对象,再逐个生成URL并获取元数据:
def get_all_s3_images(bucket_name, prefix='index/'): response = s3_client.list_objects_v2(Bucket=bucket_name, Prefix=prefix) image_list = [] if 'Contents' in response: for obj in response['Contents']: obj_key = obj['Key'] # 获取元数据(S3会把元数据键转为小写) meta = s3_client.head_object(Bucket=bucket_name, Key=obj_key)['Metadata'] full_name = meta.get('fullname', 'Unknown') # 生成预签名URL img_url = generate_presigned_url(bucket_name, obj_key) image_list.append({'url': img_url, 'alt': full_name}) return image_list # 获取所有图片信息,传递给前端遍历展示 all_images = get_all_s3_images('rekognition-pictures')
内容的提问来源于stack exchange,提问作者F128115

