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

如何使用Python Discord机器人实现!gif指令返回对应搜索词GIF

Discord 机器人GIF搜索功能修正实现

原代码可直接定位的问题点

  • 存在运行即报错的硬bug:引用了未定义的CommandKey常量,程序启动后执行到命令判断逻辑时会直接抛出NameError崩溃
  • 核心逻辑未打通:getGIF函数仅将Tenor接口返回的原始JSON打印到控制台,既没有提取可直接展示的GIF直链,也没有将内容发送到Discord聊天频道
  • 关键词提取逻辑鲁棒性极差:靠固定字符位置硬切字符串获取搜索词,只要用户输入时命令和关键词之间多打空格、或者没留空格,拿到的搜索词就是完全错误的
  • 架构存在阻塞隐患:requests是同步网络库,直接放在Discord的异步事件循环里调用,一旦接口请求耗时几秒,整个机器人会完全卡死,无法响应其他用户的消息
  • 接口返回解析逻辑缺失:没有根据Tenor的返回结构提取有效内容,也没有做异常兜底,遇到空结果、接口报错时会直接抛出KeyError崩溃

修正后的完整可运行代码

import discord
import requests
import asyncio
from constants import TenorToken, DiscordToken

# 直接定义命令前缀,解决未定义变量的报错
CommandKey = "!"
client = discord.Client()
embedColour = 0xff0000

async def getGIF(searchTerm):
    # 以字典形式传请求参数,让requests自动做URL编码,避免特殊字符导致请求失效
    request_params = {
        "q": searchTerm,
        "key": TenorToken,
        "limit": 1,
        "contentfilter": "medium"
    }
    loop = asyncio.get_event_loop()
    # 将同步的requests请求丢到独立线程池执行,不阻塞主异步事件循环
    response = await loop.run_in_executor(
        None, 
        lambda: requests.get(
            "https://g.tenor.com/v1/search", 
            params=request_params, 
            timeout=10
        )
    )
    # 兜底判断请求状态,接口异常时直接返回空
    if response.status_code != 200:
        return None
    gif_data = response.json()
    # 判断是否存在搜索结果,空结果直接返回
    if not gif_data.get("results"):
        return None
    # 从返回结构中提取适配Discord展示的中等尺寸GIF直链,加载速度更快
    gif_url = gif_data["results"][0]["media"][0]["mediumgif"]["url"]
    return gif_url

@client.event
async def on_ready():
    print(f"{client.user}"[:-5] + " 已上线!")

@client.event
async def on_message(message):
    # 忽略自身发送的消息,避免触发逻辑死循环
    if message.author == client.user:
        return

    if message.content.lower().startswith(f"{CommandKey}gif"):
        # 根据命令的实际长度截取关键词,strip去掉前后多余空格,兼容各种输入格式
        search_term = message.content[len(f"{CommandKey}gif"):].strip()
        # 兼容用户没输入关键词的场景
        if not search_term:
            await message.channel.send("请在命令后输入要搜索的GIF关键词")
            return
        gif_link = await getGIF(search_term)
        # 根据拿到的结果发对应消息,无结果时给兜底提示
        if gif_link:
            await message.channel.send(gif_link)
        else:
            await message.channel.send("没找到匹配的GIF,换个关键词试试?")

client.run(DiscordToken)

各调整项的实现原理

  • 用字典传请求参数:手动拼URL的写法遇到带空格、特殊符号的搜索词时,会因为未做合规URL编码导致请求被Tenor接口拦截;用params参数传值时requests会自动完成编码,适配各类搜索词
  • 同步请求丢线程池执行:Discord.py的事件循环是单线程异步模型,如果直接在异步流程里跑同步的网络请求,接口等待的时间里整个机器人会完全失去响应;用线程池跑阻塞操作可以让主循环继续处理其他消息
  • 多层异常兜底:Tenor接口可能返回空结果、token失效、流量超限等异常状态,直接硬取返回字典的字段会触发程序崩溃,加状态判断可以把异常转化为用户可见的友好提示
  • 动态计算截取长度提取关键词:原来的固定字符位置截断的写法,遇到!gif funny(多空格)、!giffunny(无空格)这类输入时,会切出错误的搜索词;动态根据命令的实际长度截取,再strip掉多余空格,可以兼容用户各种输入格式

内容的提问来源于stack exchange,提问作者FlamingNinja925

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 02:06:03