Discord机器人触发429限流错误的解决方法及代码优化
解决Discord比特币统计机器人的429限流与状态缺失问题
你的问题核心是调用频率过高触发Discord API限流,同时网页爬取逻辑不合理,导致数据缺失和机器人崩溃。下面是针对性的修改方案:
原代码的关键问题
- 每3秒爬一次CoinGecko网页:完全没必要,比特币统计数据不会高频更新,还容易被目标网站反爬。
- 每3秒调用一次
change_presence:Discord对状态更新有频率限制,短时间多次调用直接触发429限流,导致机器人无响应。 - 全局变量
Count管理混乱:循环中直接修改全局变量,容易出现索引越界或状态跳变。 - 任务启动方式错误:
on_ready里直接调用命令函数,上下文传递错误,导致逻辑异常。 - 依赖固定XPath解析网页:CoinGecko页面结构一旦变化,数据就会缺失。
修改后的完整代码
改用CoinGecko官方API(更稳定),分开数据更新和状态切换的循环,缓存数据避免重复请求:
import discord from discord.ext import commands, tasks import requests import asyncio intents = discord.Intents.default() intents.message_content = True intents.members = True bot = commands.Bot(command_prefix='.', intents=intents) # 缓存统计数据和状态索引 stats_cache = [] current_stat_index = 0 # CoinGecko官方API端点 COINGECKO_API_URL = "https://api.coingecko.com/api/v3/coins/bitcoin" def fetch_bitcoin_stats(): """从CoinGecko API获取比特币统计数据,返回格式化后的列表""" try: response = requests.get(COINGECKO_API_URL, timeout=10) response.raise_for_status() data = response.json() price = f"${data['market_data']['current_price']['usd']:,.2f}" h24_change = data['market_data']['price_change_percentage_24h'] stats = [ f"1h: {data['market_data']['price_change_percentage_1h_in_currency']['usd']:.2f}%", f"24h: {h24_change:.2f}%", f"7d: {data['market_data']['price_change_percentage_7d_in_currency']['usd']:.2f}%", f"30d: {data['market_data']['price_change_percentage_30d_in_currency']['usd']:.2f}%", f"1y: {data['market_data']['price_change_percentage_1y_in_currency']['usd']:.2f}%", f"24h Low: ${data['market_data']['low_24h']['usd']:,.2f}", f"24h High: ${data['market_data']['high_24h']['usd']:,.2f}" ] return price, h24_change, stats except Exception as e: print(f"获取数据失败: {e}") return None, None, [] @tasks.loop(minutes=5) # 每5分钟更新一次数据,避免频繁请求 async def update_stats_task(): global stats_cache price, h24_change, stats = fetch_bitcoin_stats() if price and h24_change is not None and stats: stats_cache = stats # 更新机器人昵称 guild = discord.utils.get(bot.guilds, name="тесты") if guild: member = guild.get_member(1066093484890656951) if member: nick_suffix = " (↗)" if h24_change >= 0 else " (↘)" await member.edit(nick=f"{price}{nick_suffix}") @tasks.loop(seconds=3) # 每3秒切换一次状态 async def rotate_presence_task(): global current_stat_index if not stats_cache: return # 缓存为空时不切换状态 # 循环切换状态,避免索引越界 current_stat = stats_cache[current_stat_index] await bot.change_presence( activity=discord.Activity(type=discord.ActivityType.watching, name=current_stat) ) current_stat_index = (current_stat_index + 1) % len(stats_cache) @bot.event async def on_ready(): print(f"已登录为 {bot.user}") # 启动两个独立任务:数据更新和状态切换 update_stats_task.start() rotate_presence_task.start() if __name__ == "__main__": bot.run('MyTokenHere') # 替换为你的机器人令牌
关键改动说明
- 使用CoinGecko官方API:替代网页爬取,数据更稳定,避免XPath失效问题,同时合规性更好。
- 分离数据更新和状态切换:
update_stats_task每5分钟更新一次数据,大幅减少API请求频率。rotate_presence_task每3秒切换一次状态,使用缓存的数据,避免重复请求。
- 安全管理状态索引:用取模运算
(current_stat_index + 1) % len(stats_cache)保证索引不会越界,状态循环更稳定。 - 正确启动任务:在
on_ready中启动tasks.loop任务,符合discord.py规范,避免上下文错误。 - 错误处理:添加API请求的异常捕获,避免单个请求失败导致整个机器人崩溃。
额外建议
- 如果仍遇到Discord限流,可把状态切换间隔从3秒调到5秒,进一步降低调用频率。
- 可以给CoinGecko API请求添加本地缓存,避免重复请求。
- 不要频繁修改机器人昵称,当前每5分钟修改一次的频率是安全的。
内容的提问来源于stack exchange,提问作者FDFD FDFD
相关产品推荐
相关产品推荐

