Telethon的download_media方法在AWS Lambda中失效问题求助
问题:AWS Lambda中使用Telethon下载Telegram图片报错只读文件系统
我在Lambda的lambda_handler里用Telethon下载Telegram频道消息的图片,代码如下:
with TelegramClient(StringSession(string_session), api_id=int(telegram_id), api_hash=telegram_hash) as client: count = 1 for message in client.iter_messages(name, limit=limit, reverse=False): news.append(message.text) file_name = f"{str(count)}" message.download_media(file=f"/tmp/{file_name}") path = f"/tmp/{file_name}" key = None s3.upload_file(Filename=path, Bucket='telebotmedia', Key=file_name) count += 1
运行时报错:
[Errno 30] Read-only file system: 'photo_2024-01-16_17-34-40.jpg'
已经给函数角色配置了AWSLambdaBasicExecutionRole和PowerUserAccess权限,但还是没法在/tmp目录完成下载。
原因分析
报错里的文件名是photo_2024-01-16_17-34-40.jpg,但你指定的路径是/tmp/{count},说明Telethon在下载时自动给文件追加了原始后缀,导致实际写入的路径不是你指定的/tmp/1,而是直接在Lambda的只读工作目录生成带后缀的文件,最终触发权限错误。
解决方法
方法1:明确指定完整带后缀的/tmp路径
先获取媒体文件的原始后缀,再拼接成完整的/tmp路径,确保Telethon写入到正确的可写目录:
with TelegramClient(StringSession(string_session), api_id=int(telegram_id), api_hash=telegram_hash) as client: count = 1 for message in client.iter_messages(name, limit=limit, reverse=False): news.append(message.text) # 跳过非媒体消息 if not message.media: count += 1 continue # 获取文件后缀 if message.photo: # 图片取最后一个尺寸的文件名后缀 file_ext = message.photo.file.name.split('.')[-1] elif message.document: # 文档直接取原始文件名的后缀 file_ext = message.document.file.name.split('.')[-1] else: count += 1 continue # 拼接完整的可写路径 file_name = f"{count}.{file_ext}" file_path = f"/tmp/{file_name}" message.download_media(file=file_path) s3.upload_file(Filename=file_path, Bucket='telebotmedia', Key=file_name) count += 1
方法2:跳过本地文件,直接上传字节流到S3
不需要写入/tmp目录,直接把Telethon下载的媒体内容转成字节流上传,彻底避免文件系统问题:
with TelegramClient(StringSession(string_session), api_id=int(telegram_id), api_hash=telegram_hash) as client: count = 1 for message in client.iter_messages(name, limit=limit, reverse=False): news.append(message.text) if not message.media: count += 1 continue # 定义S3存储的文件名 if message.photo: file_name = f"{count}.jpg" elif message.document: # 优先用原始文件名,没有则自定义 file_name = message.document.file.name or f"{count}.bin" # 直接下载字节流并上传到S3 media_bytes = message.download_media(bytes) s3.put_object(Bucket='telebotmedia', Key=file_name, Body=media_bytes) count += 1
额外注意点
- Lambda的
/tmp目录最大容量为512MB,批量下载时要注意控制文件总大小。 - Lambda执行结束后,
/tmp目录的文件会自动清理,无需手动删除。
内容的提问来源于stack exchange,提问作者Furkan Suren
相关产品推荐
相关产品推荐

