Discord.py机器人实现Epic商店免费游戏更新自动通知
Epic免费游戏自动推送Discord机器人调整方案
要实现免费游戏更新时自动发通知,核心是把现有手动触发的指令逻辑,改成后台定时轮询+新内容去重校验的模式,不需要用户发送指令,机器人自动检测更新推送,具体调整步骤如下:
- 首先把拉取Epic免费游戏的逻辑从指令函数里抽离成独立公共方法,脱离Discord指令上下文依赖,方便定时任务直接调用
- 增加本地持久化记录,保存已经推送过的免费游戏标识(比如游戏ID或者标题),避免重复推送同一款游戏的通知,用本地json文件存储即可,不需要额外搭数据库
- 用discord.py内置的定时任务扩展做周期轮询,建议轮询间隔设为30~60分钟,Epic免费游戏固定每周更新,轮询太频繁容易触发接口限流
- 修复原代码的几个逻辑问题:原代码只取列表第一个游戏,多游戏同期限免会漏推;原代码接口区域和商店链接区域不匹配,会导致跳转链接失效;原代码直接捕获所有异常不打印日志,出问题无法排查
调整后可直接运行的参考代码
import discord from discord.ext import commands, tasks import requests import json import os bot = commands.Bot(command_prefix="!", intents=discord.Intents.default()) # 配置要推送通知的频道ID,提前在Discord开发者模式下复制 NOTIFY_CHANNEL_ID = 123456789012345678 # 存储已推送游戏记录的本地文件路径 RECORD_FILE_PATH = "epic_free_games_record.json" def load_pushed_records(): """读取已经推送过的游戏记录""" if not os.path.exists(RECORD_FILE_PATH): return [] with open(RECORD_FILE_PATH, "r", encoding="utf-8") as f: return json.load(f) def save_pushed_records(record_list): """保存已推送的游戏记录到本地""" with open(RECORD_FILE_PATH, "w", encoding="utf-8") as f: json.dump(record_list, f, ensure_ascii=False, indent=2) def fetch_current_free_games(): """拉取当前Epic商店的免费游戏列表""" ENDPOINT = "https://store-site-backend-static.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN" resp = requests.get(ENDPOINT, timeout=10) resp.raise_for_status() raw_data = resp.json() game_list = raw_data["data"]["Catalog"]["searchStore"]["elements"] free_games = [] for game in game_list: # 过滤出当前处于限免期的游戏 promotions = game.get("promotions", {}) if promotions and promotions.get("promotionalOffers"): # 提取游戏标题、商品页slug用来拼链接 free_games.append({ "title": game["title"], "slug": game.get("productSlug", "") }) return free_games @tasks.loop(minutes=60) async def check_epic_free_games(): """定时任务:每小时检查一次Epic免费游戏更新""" channel = bot.get_channel(NOTIFY_CHANNEL_ID) if not channel: return try: current_free = fetch_current_free_games() pushed_records = load_pushed_records() # 找出还没推送过的新限免游戏 new_games = [g for g in current_free if g["title"] not in pushed_records] if new_games: for game in new_games: shop_url = f"https://www.epicgames.com/store/zh-CN/product/{game['slug']}" await channel.send(f"**{game['title']}** 现在可以在Epic商店免费领取啦!\n领取链接:{shop_url}") pushed_records.append(game["title"]) # 更新本地记录 save_pushed_records(pushed_records) except Exception as e: # 打印异常方便排查,不要裸吞错误 print(f"检查Epic免费游戏出错:{str(e)}") @bot.event async def on_ready(): # 机器人启动后开启定时检查任务 if not check_epic_free_games.is_running(): check_epic_free_games.start() print(f"机器人已登录:{bot.user}") # 保留原来的手动查询指令 @bot.command(name='free', aliases=['fr']) async def free(ctx): try: current_free = fetch_current_free_games() if not current_free: await ctx.send("当前没有可领取的免费游戏") return msg = "当前Epic可免费领取的游戏:\n" for game in current_free: shop_url = f"https://www.epicgames.com/store/zh-CN/product/{game['slug']}" msg += f"- **{game['title']}**:{shop_url}\n" await ctx.send(msg) except Exception as e: await ctx.send(f"查询免费游戏失败:{str(e)}") # 替换成你自己的机器人Token bot.run("YOUR_BOT_TOKEN_HERE")
注意事项
- 第一次运行的时候会把当前所有在限免的游戏都推送一遍,如果不想第一次触发全量推送,可以先手动跑一次
fetch_current_free_games把现有游戏标题存到记录文件里 - 轮询间隔不要低于10分钟,过高的请求频率可能会被Epic接口拦截
- 如果需要推送到多个频道,修改通知频道配置,遍历多个频道ID发送消息即可
内容的提问来源于stack exchange,提问作者Python Guy
相关产品推荐
相关产品推荐

