You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用discord.py开发mcoc.py cog命令时触发RuntimeError: This event loop is already running错误的原因与修复方案咨询

解决discord.py命令中requests-html渲染时的RuntimeError问题

错误原因

你碰到的这个RuntimeError: This event loop is already running,核心问题在于discord.py本身已经在运行一个asyncio事件循环,而requests-html的render()方法底层会尝试调用loop.run_until_complete()去启动另一个独立的事件循环。但asyncio的规则是同一个线程里不能同时运行多个事件循环,这就直接导致了冲突报错。

另外顺便提一句,你代码里有个小笔误:champname=="blackwidow_timely"是比较操作,不是赋值,应该改成champname = "blackwidow_timely",不然这个别名替换根本不会生效。

修复方案

方案1:用nest_asyncio允许嵌套事件循环(快速解决)

这是最省事的临时解决方案,只需要引入nest_asyncio库来让asyncio支持嵌套运行事件循环:

  1. 先安装库:
pip install nest_asyncio
  1. 在你的mcoc.py文件开头添加:
import nest_asyncio
nest_asyncio.apply()

把这段代码放在所有导入语句之后、命令定义之前就行。它会修改asyncio的默认行为,允许在已运行的事件循环里再启动新的循环,从而解决冲突。

方案2:改用纯异步的网页处理流程(更稳定推荐)

requests-html的异步封装有时候和discord.py的事件循环兼容性不佳,更稳妥的方式是直接用pyppeteer(无头浏览器)做异步渲染,再用BeautifulSoup解析内容。这样完全贴合discord.py的异步生态,不会有循环冲突问题:

首先安装依赖:

pip install pyppeteer beautifulsoup4 aiohttp

然后修改你的命令代码:

import pyppeteer
from bs4 import BeautifulSoup

@commands.command()
async def mcoc(self, ctx, tier_str:int,*,champname:str):
    champname = champname.strip().lower()
    # 修正笔误:把比较改成赋值
    if champname == "bwcv":
        champname = "blackwidow_timely"
    url = f"https://auntm.ai/champions/{champname}/tier/{tier_str}"
    
    # 异步启动无头浏览器并渲染页面
    browser = await pyppeteer.launch(headless=True)
    page = await browser.newPage()
    await page.goto(url)
    await page.waitForTimeout(1000)  # 等待1秒让内容加载
    await page.evaluate('window.scrollTo(0, document.body.scrollHeight)')  # 滚动到底部
    html_content = await page.content()
    await browser.close()
    
    # 解析HTML内容
    soup = BeautifulSoup(html_content, 'html.parser')
    # 注意:网站的动态类名可能会变,建议后续换成更稳定的选择器(比如元素属性/层级)
    info_element = soup.find("div", class_="sc-hiSbYr XqbgT")
    name_element = soup.find('div', class_="sc-cxFLnm izBVou")
    
    # 处理可能的元素未找到情况
    champ_display_name = name_element.text.strip() if name_element else champname.title()
    tier_info = info_element.text.strip() if info_element else "无法获取Tier信息"
    
    # 发送Embed(修正typing的语法错误:要加括号)
    async with ctx.typing():
        embed = discord.Embed(title=f"{champ_display_name}",
                              description=f"More Information about {champ_display_name} can be found [here]({url})")
        # 可以把Tier信息加到Embed里
        embed.add_field(name="Tier信息", value=tier_info, inline=False)
        await ctx.send(embed=embed)

额外注意事项

  • 网站的动态生成类名(比如sc-hiSbYr XqbgT)很可能会在网站更新后失效,建议后续用更稳定的选择方式,比如基于元素的id、data-*属性,或者元素的层级结构来定位。
  • 你原来的代码里ctx.typing()少了括号,应该写成async with ctx.typing():,否则会报错。
  • 方案2虽然代码多一点,但完全基于异步原生实现,长期来看更稳定,不容易出现奇怪的异步冲突问题。

内容的提问来源于stack exchange,提问作者Dheeraj-Tech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 12:33:12