如何让Python开发的Discord机器人每周日自动发送课程表截图?
Discord机器人定时发送课程表问题解决方案
问题根源
- 事件循环阻塞:原代码中
while True的schedule轮询循环会完全阻塞discord.py的异步事件循环,导致机器人无法处理任何Discord事件(包括消息发送、指令响应)。 - 异步函数调用错误:
continuation是异步函数,在同步的job函数中直接调用不会执行,必须通过事件循环调度。 - 频道对象获取失败:
bot.get_channel()未传入具体的频道ID,无法获取有效频道对象。 - 周数未实时更新:
my_date在程序启动时初始化,定时任务运行时不会自动更新为当前周数。
修正后的完整代码
import discord from discord.ext import commands, tasks from selenium import webdriver from selenium.webdriver.chrome.options import Options import time import pyautogui import datetime from datetime import date # 配置参数 BOT_TOKEN = "你的机器人令牌" TARGET_CHANNEL_ID = 123456789012345678 # 替换为目标频道ID DEFAULT_CLASS_ID = "myclassname" bot = commands.Bot(command_prefix="!", intents=discord.Intents.all()) @bot.event async def on_ready(): print("Bot is alive") try: synced = await bot.tree.sync() print(f"同步了 {len(synced)} 条命令") except Exception as e: print(e) # 启动定时任务 weekly_schedule_task.start() # 复用的课程表生成与发送函数 async def generate_and_send_schedule(channel, classid=DEFAULT_CLASS_ID): # 获取当前周数 my_date = date.today() year, week_num, day_of_week = my_date.isocalendar() driver = webdriver.Chrome() try: driver.get('school.com') driver.set_window_size(1024, 768) time.sleep(3) pyautogui.moveTo(1000, 440, duration=1) pyautogui.click(1000, 440) pyautogui.typewrite(classid) pyautogui.typewrite(["enter"]) time.sleep(3) driver.execute_script("window.scrollTo(0,document.body.scrollHeight)") time.sleep(2) driver.save_screenshot('screenshot.png') await channel.send(f"第 {week_num} 周 {classid} 的课程表") await channel.send(file=discord.File('screenshot.png')) finally: driver.quit() # 确保浏览器关闭 # 指令触发的功能 @bot.command() async def schema1(ctx, classid=DEFAULT_CLASS_ID): await generate_and_send_schedule(ctx.channel, classid) # 定时任务:每周日15:00执行 @tasks.loop(time=datetime.time(hour=15, minute=0, tzinfo=datetime.timezone.utc)) # 注意时区,根据你的地区调整 async def weekly_schedule_task(): # 检查当前是否是周日(isocalendar的day_of_week=7代表周日) if date.today().isocalendar()[2] == 7: channel = bot.get_channel(TARGET_CHANNEL_ID) if channel: await generate_and_send_schedule(channel) print("定时任务执行完成") else: print("无法获取目标频道,请检查频道ID是否正确") bot.run(BOT_TOKEN)
关键修改说明
- 使用discord.py tasks扩展:替代schedule库,基于异步事件循环运行定时任务,不会阻塞机器人的正常运行。
- 复用核心逻辑:把课程表生成和发送的逻辑封装成
generate_and_send_schedule函数,指令触发和定时任务都调用这个函数,减少重复代码。 - 实时更新周数:在每次生成课程表时重新获取当前日期,确保周数是最新的。
- 正确处理异步调用:所有Discord相关操作都通过await执行,确保在事件循环中处理。
- 时区处理:定时任务的time参数需要设置正确的时区,避免时间偏差(示例用UTC,根据你的实际时区调整,比如东八区可以用
datetime.timezone(datetime.timedelta(hours=8)))。 - 资源清理:使用try-finally确保浏览器驱动在任务完成后关闭,避免资源泄漏。
内容的提问来源于stack exchange,提问作者ullman
相关产品推荐
相关产品推荐

