discord.py无法获取用户头像平均颜色,求排查解决
问题分析与解决方案
嘿,这个问题我之前做Discord Bot的时候也碰到过!主要是两个关键点导致的,咱们一个个拆解:
1. Discord CDN 的请求拦截
Discord的头像CDN服务器会对没有合理User-Agent标识的请求直接拦截,返回403或者其他非200状态码。你用requests的时候,它默认的User-Agent是类似requests/2.31.0的格式,Discord会放行;但aiohttp默认的User-Agent是Python/3.x aiohttp/3.x,这种太“朴素”的标识会被判定为可疑请求直接打回来,你的代码就触发异常返回默认值了。
2. 不合理的ClientSession创建方式
你的代码每次调用函数都新建一个ClientSession,这其实违反了aiohttp的最佳实践——频繁创建销毁会话会浪费资源,还可能导致连接池管理混乱。而且discord.py的Bot本身就自带了一个已经初始化好的aiohttp会话,完全没必要自己再新建。
修复后的代码
针对这两个问题,我们做两处关键调整:
- 给请求添加符合浏览器标准的User-Agent
- 复用Bot实例自带的aiohttp会话
import discord from discord.ext import commands from PIL import Image from io import BytesIO class Bot(commands.Bot): ... async def get_average_colour(self, image_url, default=0x696969): # 去掉@staticmethod,这样才能访问Bot实例的session # 用一个常见浏览器的User-Agent,避免被CDN拦截 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" } try: # 直接使用Bot自带的session,不用每次新建 async with self.session.get(image_url, headers=headers) as resp: if resp.status != 200: raise Exception(f"请求失败,状态码: {resp.status}") # 读取响应内容 img_data = await resp.read() img = Image.open(BytesIO(img_data)) # 计算平均颜色——注意新版本PIL里ANTIALIAS已经废弃,用LANCZOS替代 colour = img.resize((1, 1), Image.Resampling.LANCZOS).getpixel((0, 0)) return int("{:02x}{:02x}{:02x}".format(*colour), 16) except Exception as e: # 可以加个打印方便调试,上线后可以去掉 print(f"获取平均颜色失败: {str(e)}") return default ...
额外小提示
- 关于
Image.ANTIALIAS:在PIL 9.1.0及以上版本中,ANTIALIAS已经被标记为过时,推荐用Image.Resampling.LANCZOS替代,这样兼容性更好。 - User-Agent可以随便选一个主流浏览器的标识,不一定非要用上面的,只要不是aiohttp的默认值就行。
- 去掉
@staticmethod很重要,因为这样我们才能访问Bot实例自带的session——这个会话是Bot启动时就初始化好的,稳定又高效。
你现在试试这个修改后的函数,应该就能正常获取用户头像的平均颜色啦!
内容的提问来源于stack exchange,提问作者BluePigeon
相关产品推荐
相关产品推荐

