如何使用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
相关产品推荐
相关产品推荐

