如何使用discord.py创建Discord频道聊天归档文件?
Discord.py频道聊天归档可行实现方案
核心思路
因为discord-components与chat_exporter存在已知冲突,本方案完全不依赖第三方导出库,手动实现HTML生成+文件发送全逻辑,无额外依赖,不会触发兼容问题。
问题1:生成文件无法发送的修复
常见触发原因是文件写入时被进程锁定,或发送时参数错误,可按照以下方案处理:
- 保证文件写入完成、流关闭后再调用发送接口,不要在文件写入的上下文管理器内执行发送操作
- 优先使用
BytesIO实现内存生成文件,避免本地磁盘写入的权限、路径、文件锁定问题 - 正确示例代码:
import discord from io import BytesIO # 生成HTML内容后直接转为内存文件发送 async def send_archive(html_content, ctx): file_io = BytesIO(html_content.encode("utf-8")) file_io.seek(0) # 重置文件指针到开头,否则读取内容为空 await ctx.send(file=discord.File(file_io, filename="chat_archive.html"))
如果需要留存本地文件,写法如下:
html_content = "你的HTML内容" file_path = "chat_archive.html" # 写入文件 with open(file_path, "w", encoding="utf-8") as f: f.write(html_content) # 退出with块后文件已关闭,再执行发送 await ctx.send(file=discord.File(file_path))
问题2:HTML样式不达标的解决方案
直接使用内嵌CSS的单文件HTML模版,所有样式内置,无需加载外部资源,打开即可呈现票务机器人常用的深色主题归档效果,参考模版如下:
# 整体HTML归档模版,所有样式内置 HTML_TEMPLATE = """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>聊天归档</title> <style> * {margin: 0;padding: 0;box-sizing: border-box;font-family: system-ui, -apple-system, sans-serif;} body {background: #36393f;color: #dcddde;padding: 24px;max-width: 1200px;margin: 0 auto;} .archive-head {padding-bottom: 16px;border-bottom: 1px solid #42464d;margin-bottom: 24px;} .archive-head h2 {color: #fff;margin-bottom: 8px;} .archive-head p {color: #a3a6aa;font-size: 0.9rem;} .msg-item {display: flex;gap: 16px;padding: 12px 8px;border-radius: 4px;margin-bottom: 8px;} .msg-item:hover {background: #32353b;} .avatar {width: 40px;height: 40px;border-radius: 50%;flex-shrink: 0;} .msg-body {flex: 1;min-width: 0;} .msg-head {display: flex;align-items: center;gap: 10px;margin-bottom: 4px;} .username {font-weight: 600;color: #fff;} .time {font-size: 0.75rem;color: #a3a6aa;} .msg-content {line-height: 1.6;word-wrap: break-word;} .msg-img {max-width: 400px;max-height: 300px;border-radius: 4px;margin-top: 8px;} .msg-attachment {margin-top: 8px;color: #00aff4;} </style> </head> <body> <div class="archive-head"> <h2>频道:{channel_name}</h2> <p>归档生成时间:{gen_time}</p> <p>消息总数:{msg_count} 条</p> </div> <div class="msg-list">{msg_html}</div> </body> </html> """ # 单条消息渲染模版 MSG_TEMPLATE = """ <div class="msg-item"> <img class="avatar" src="{avatar}" alt="{author}"> <div class="msg-body"> <div class="msg-head"> <span class="username">{author}</span> <span class="time">{send_time}</span> </div> <div class="msg-content">{content}</div> {attachments} </div> </div> """
归档内容生成逻辑
from datetime import datetime async def gen_archive_html(channel): # 拉取历史消息,按时间正序排列 messages = await channel.history(oldest_first=True).flatten() msg_html_list = [] for msg in messages: # 处理附件 attach_html = "" for att in msg.attachments: if att.content_type and att.content_type.startswith("image/"): attach_html += f'<img class="msg-img" src="{att.url}" alt="附件">' else: attach_html += f'<p class="msg-attachment">附件:{att.filename}</p>' # 渲染单条消息,默认头像可替换为base64编码实现无外链 default_avatar = "data:image/png;base64,此处替换为你自己的默认头像base64编码" msg_html = MSG_TEMPLATE.format( avatar=msg.author.avatar.url if msg.author.avatar else default_avatar, author=msg.author.display_name, send_time=msg.created_at.strftime("%Y-%m-%d %H:%M:%S"), content=msg.content.replace("\n", "<br>"), attachments=attach_html ) msg_html_list.append(msg_html) # 渲染完整HTML full_html = HTML_TEMPLATE.format( channel_name=channel.name, gen_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), msg_count=len(messages), msg_html="".join(msg_html_list) ) return full_html
完整调用示例
# 绑定到discord.py命令 @bot.command() async def export_archive(ctx): html = await gen_archive_html(ctx.channel) await send_archive(html, ctx) await ctx.send("聊天归档已生成并发送")
如需完全无外部资源,可将所有资源链接转换为base64编码内嵌到HTML中,无需依赖任何外部链接。
内容的提问来源于stack exchange,提问作者Mdog504
相关产品推荐
相关产品推荐

