『Nonebot 插件编写教程』nonebot2处理消息的完整过程

news2024/9/20 7:47:29

文章目录

  • 前言
  • 捕获消息
  • 处理消息
    • Bot机器人参数
    • Event事件参数
  • 回复消息
    • 字符串与Message
    • 调用MessageSegment接口

前言

在这里插入图片描述
在这里插入图片描述

前面已经有不止一篇博客教大家如何搭建nonebot2环境了大家可以去专栏查看,这篇博客并不会再次带大家来搭建nonebot2环境,而是着手与插件的编写,也就是开始使用机器人处理QQ用户发来的消息。在说插件编写之前先带大家回顾一下Nonebot2机器人处理用户信息的整体过程。机器人后台接收消息时会经过如下流程:首先gocqhttp会从QQ服务器获取消息,然后通过接口将消息传输给Nonebot2,Nonebot2将消息处理的结果再发给gocqhttp端,最后gocqhttp根据发还的数据向QQ服务器发出消息,这就是消息收发与处理的整个流程。简单来说gocqhttp就是实现Nonebot2和QQ服务器之间通信的桥梁,也就是眼睛耳朵鼻子或者说身体的各个部位,而Nonebot2就是相当于"大脑",负责处理接收到的信息并且发送指令给手、脚这种身体部位让他们行动,今天要编写的插件就是大脑中的神经元,不同的神经元负责处理不同类型的消息。

接下来将分为三部分进行介绍,捕获消息就是用户的消息触发到Nonebot2的神经元,处理消息就是Nonebot这个大脑如何处理捕获到的消息,回复消息是指做出了什么行为。先结合一个实例观察一下:

from nonebot import on_keyword
# nonebot2中的适配器这么引入
from nonebot.adapters.onebot.v11 import Message

helloword=on_keyword({"hello"})

@helloword.handle()
async def _():
    await helloword.finish(Message("你好!"))

这段代码实现的功能是:如果有人发送(无论是与机器人的私聊还是群聊里)任一包含"hello"这个关键词的消息的时候,机器人会回复消息:“你好!”。

接下来的三部分将会由这段简短的代码进行展开叙述。在正式展开之前先对Nonebot2引入基本库进行一下说明。

from nonebot import on_keyword
from nonebot.adapters.onebot.v11 import Message

这段import代码的是从nonebot2库中引入on_keyword方法,再从Onebot V11库中引入Message方法,后面会介绍这两个有啥用。

Nonebot2中的很多功能都需要通过import导入后才能使用,这里列举了一些常见库里包含的常见函数:(大家只需先记住引入库从哪里引入即可)

常用函数/方法说明
noneboton_message,on_notice,on_request,on_keyword,on_command,on_regex基础库
nonebot.configConfig配置文件库
nonebot.matcherMatcher事件响应器
nonebot.paramsArg,State,CommandArgs,RegexMatched参数库
nonebot.permissionSUPERUSER,Permission权限库
nonebot.loglogger,default_format日志库
nonebot.adapters.onebot.v11Bot,Message,MessageSegment,Event,PRIVATE,GROUP等Onebot库

注:OneBot V11的库可以从nonebot.adapters.onebot.v11直接导入,也可以用诸如nonebot.adapters.onebot.v11.message的方式导入

捕获消息

helloword=on_keyword({"hello"})

这行代码的含义是“创建一个名为helloword的变量,其为一个类型为on_keyword的事件响应器”,这段代码的作用就是当用户发送的信息包含hello时就触发其绑定的函数,而helloword的作用仅仅是方便找到这个响应器。在此大家可以了解一下有关on_keyword的参数。

on_keyword(keywords, rule=..., *, permission=..., handlers=..., temp=..., priority=..., block=..., state=...) 注册一个消息事件响应器,并且当消息纯文本部分包含关键词时响应

  • 第一个参数是keywords,类型为集合(Set),传入的是用来触发该响应器工作的关键词集合(用{}包起来的)。

  • 第二个参数是rule,传入的是bool类型规则函数或者Rule类。

  • 第三个参数是permission,传入的是bool类型的权限函数或者Permission类。

  • 第四个参数是handlers,传入的参数是被事件响应器触发的函数列表。

  • 第五个参数是temp,传入的是bool类型参数,若为True则此响应器只会使用一次。

  • 第六个参数是priority,传入的是int型参数,用于设定响应器的优先级。注意!此参数越大优先级越低

  • 第七个参数是block,传入的是bool类型的参数,若为True则不会注册优先级小于此响应器的响应器,相当于消息被阻断在这里了。

  • 最后一个参数是state,传入的是字典类型参数,用于存储响应器状态信息。

目前需要了解的只有keywordsrule,permissionpriorityblock这四个参数,其他参数用法较为麻烦,我们之后才会讲到

  • 首先是介绍的是keywords参数,这个参数作用比较简单,就是传入一个元素是字符串的集合,然后如果接收到的消息包含这个集合内的任一关键字,则触发该事件响应器。

  • 第二个是rule参数,通过这个参数我们可以过滤掉想过滤掉的语句,有两种方式,一个是自定义规则,一个是使用官方的rule库。rule参数的本质其实就是一个bool类型的变量或者返回值类型为bool的函数,当rule值为True时即可以触发事件响应器,反之为False时则不会触发。或许有人会问在响应器处理函数当中判断是否符合条件和rule的功能是不是一样的?虽然作用上两者一样,但是ruler相当于从源头上"掐断"该事件响应器,而处理函数是从中途阻止。

    # 自定义规则函数(当@机器人时触发)
    from nonebot import on_keyword
    from nonebot.adapters.onebot.v11 import GroupMessageEvent
    def _checker(event: GroupMessageEvent) -> bool :
        return event.to_me
    helloword=on_keyword({"hello"},rule=_checker)
    # 使用官方的规则库(当@机器人时触发)
    from nonebot import on_keyword
    from nonebot.rule import to_me
    
    helloword=on_keyword({"hello"},rule=to_me())
    
  • 第三个是permission参数,这个参数负责传入能触发此事件响应器的消息发送者类型,也就是哪些人能触发这个响应器。一般来说重要的指令都会加上一些权限限制,诸如操作机器人后台的一些指令。常见的permission有SUPERUSER(写在.env文件中的超级用户),GROUP_ADMIN(群管理员)和GROUP_OWNER(群主),这些是框架本身提供的。除此以外我们也可以自定义权限组,当然这个内容之后再谈。

  • 第四个参数是priority,负责调控响应器触发的优先级,优先级越高,就越早被执行。举个例子,如有以下代码

    helloword=on_keyword({"hello"},priority=60)
    helloword_2=on_keyword({"hello"},priority=50)
    

    两个响应器都以"hello"作为触发词,这时候如果接收到了包含"你是谁"的消息后,二者执行顺序就由priority值来决定了。注意!priority值越小,优先级越高!如上面那个例子中helloword_2就会比helloword要更早触发。

    最后一个介绍的是block参数,这个参数一般情况下是和前面那个priority参数搭配起来用,用以阻断消息传递。还是以上面那段代码为例

    helloword=on_keyword({"hello"},priority=60,block=True)
    helloword_2=on_keyword({"hello"},priority=50,block=True)
    

    用户输入"hello"后并不会触发两个响应器,而是只会触发优先级更高的那个也就是helloword_2,触发完之后因为block值为True,所以消息传到这里就被阻断了,也就没办法触发优先级更低的响应器了。

处理消息

处理消息这部分需要先知道用户发送的什么然后才能处理,所以我们需要先了解Nonebot2的特性—依赖注入。

事件响应器函数常用的传入参数一般有以下三种:bot(机器人)event(事件)以及args(参数),不过除此之外还有state,match等。这里我们先只讲前两个,第三个args参数我们暂时还用不到。

Bot机器人参数

首先是第一种参数:bot,bot类型的传入参数类就只有一个:Bot,下面是使用样例

from nonebot import on_keyword
from nonebot.adapters.onebot.v11 import Bot
helloword=on_keyword({"hello"})
@helloword.handle()
async def _(bot: Bot):
    await helloword.finish(str(bot.self_id))

在上述代码中可以看到,Bot作为一个参数传入事件响应器函数当中使用。Bot是Nonebot库提供的一个类,当使用机器人的时候会自动创建一个Bot类,然后我们可以通过这个类来调用与机器人交互的各种属性与方法。比如上面例子当中的self_id就是Bot类的一个属性,返回的数据是当前bot的QQ号,类型为int(所以才要转换为str类型,不然会报参数类型不匹配的错误,因为finish方法不支持传入int型参数)。

Bot类有如下的属性

属性名返回值类型说明
self_idint(整数型)机器人自己的QQ号
adapteradapter(协议适配器)返回机器人所用的协议适配器

还有一些个人认为的Bot中比较常用的方法,篇幅有限其他方法以及具体的参数传递就不讲了,可以自行翻阅文档。

方法名作用
send_msg发送(群聊/私聊)消息
delete_msg撤回消息
set_group_ban设置群组禁言
set_friend_add_request设置好友验证是否通过
set_group_add_request设置加群验证是否通过
get_login_info获取登录信息
get_group_member_info获取指定群成员信息
get_group_honor_info获取群荣誉(龙王等)信息

Event事件参数

接下来是第二种参数:event事件参数,event类型其实包含很多类:如Event,GroupMessageEvent,PrivateMessageEvent等等。Event类一些方法/属性和Bot类重复,比如self_id等,不过由于Event类下的方法/属性相较于Bot类更多,且通用性更好,所以要获取的信息相同时一般常用Event类来代替Bot类。下面列举了一些常见的Event类

类名说明
Event事件
GroupMessageEvent群消息事件
PrivateMessageEvent私聊消息事件
NoticeEvent通知事件
GroupUploadNoticeEvent群文件上传事件
GroupAdminNoticeEvent群管理员变动事件
GroupDecreaseNoticeEvent群人数减少事件
GroupIncreaseNoticeEvent群人数增加事件
GroupBanNoticeEvent群管理员禁言事件
FriendAddNoticeEvent好友增加事件
GroupRecallNoticeEvent群消息撤回事件
FriendRecallNoticeEvent私聊消息撤回事件
NotifyEvent提醒事件(这个文档没翻到)
PokeNotifyEvent群戳一戳事件
HonorNotifyEvent群荣誉变更事件
LuckyKingNotifyEvent群红包运气王事件
RequestEvent请求事件
FriendRequestEvent好友申请事件
GroupRequestEvent入群申请事件

虽然没全部列举出来,但是这些类目前来说已经完全够用了,如何知道它们下面有哪些属性和方法呢?有两种方法:一是查阅官方文档,二是在支持代码补全的编辑器中输入对应的类名后再加上.就可以跳出对应的提示,然后可以根据语法提示选择需要的方法/属性就行了。

最后再附上一个具体例子

from nonebot import on_keyword
from nonebot.adapters.onebot.v11 import Message,GroupMessageEvent

helloword=on_keyword({"hello"})

@helloword.handle()
async def _(event:GroupMessageEvent):
    if(event.user_id==123456 and event.group_id==11111):
        await word.finish(Message("OK!"))

此段代码作用:当群聊11111中里有一个QQ号为123456的人发送包含“hello”这个词的句子时,bot会发送“OK”。

回复消息

最后我们要解决的问题是:如何将处理好的消息发送出去,在此之前我们需要了解一下Onebot的消息类型。上面我们曾提到helloword.finish()方法可以传入四种参数:

  • 字符串(Str)

  • 消息(Message)

  • 格式化消息模板(MessageTemplate)

  • 消息段(MessageSegment)

    其中格式化消息模板用法比较特殊,暂且避开不谈,只讲剩下三种。

字符串与Message

字符串(Str)与消息(Message)大部分情况下可以等价,可以替代Message使用,但是有一种特殊情况:消息内包含CQ码的时候只能使用Message,不过个人建议还是统一使用Message来进行消息发送。

CQ码是go-cqhttp协议中的一种特殊的消息字段,用以发送QQ中的特殊消息(如图片、语音、@等等),常见的CQ码格式为[CQ:类型,参数=值,参数=值],如下面的例子就是CQ码的一种使用

举出一个CQ码回复消息的例子:

@word.handle()
async def _():
    await word.finish(Message("[CQ:share,url=https://www.baidu.com,title=百度]"))

上述代码发送了一个百度的链接(不是以文字链接的方式),而是一个可以点击的类似“小程序”的执行框,点击后可以直接跳转。

(因为QQ接口的问题,此CQ码有时候会无法使用,会报错"消息可能被风控",请尝试其他的CQ码。)

这里我列举了一些常见的CQ码,全部的CQ码请查阅go-cqhttp文档或者OneBot文档。

类型参数作用
faceid=表情ID发送QQ内的表情
recordfile=文件路径/URL发送语音(一般为mp3格式)
atqq=QQ号,(name=昵称)@某人(不在群里时可以使用name参数)
shareurl=网站链接,name=网站名发送网站分享
musictype=歌曲平台,id=歌曲ID发送音乐
image参数较多,参见文档发送图片
replyid=回复的消息ID,text=消息内容发送回复消息

调用MessageSegment接口

除了CQ码之外还有一种叫消息段(MessageSegment)的东西,可以实现与CQ码相同的功能,并且还可以做一些CQ码无法做到的事情。此外官方推荐使用消息段来替代CQ码(原因:CQ码不方便+容易被注入),后续案例也都会使用消息段。用法如下

@word.handle()
async def _():
    await word.finish(MessageSegment.share(url="https://www.baidu.com",title="百度"))

此段代码效果与CQ码回复无异。使用MessageSegment方式发送特殊消息更加方便明了

提示:MessageSegment和Message可以通过"+"直接拼在一起,形成"文字+图片"类型的消息,另外Message之间也可以相互拼接。Message相当于一个数组,可以容纳一定数量的同类(Message)以及MessageSegment

最后再回顾一下使用CQ码回复消息与使用消息段回复消息的区别:

CQ码

from nonebot import on_keyword
from nonebot.adapters.onebot.v11 import Message,GroupMessageEvent
from nonebot.rule import to_me

helloword=on_keyword({"hello"},rule=to_me())

@helloword.handle()
async def _(event: GroupMessageEvent):
    await helloword.finish(Message(f"[CQ:at,qq={event.user_id}],你@我了!"))

消息段(推荐)

from nonebot import on_keyword
from nonebot.adapters.onebot.v11 import Message,GroupMessageEvent,MessageSegment
from nonebot.rule import to_me

helloword=on_keyword({"hello"},rule=to_me())

@helloword.handle()
async def _(event: GroupMessageEvent):
    await helloword.finish(MessageSegment.at(event.user_id))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/190210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【微服务】Sentinel规则持久化

Sentinel 规则持久化 一、修改微服务 修改微服务&#xff0c;让其监听Nacos中的sentinel规则配置。 具体步骤如下&#xff1a; 1.引入依赖 在order-service中引入sentinel监听nacos的依赖&#xff1a; <dependency><groupId>com.alibaba.csp</groupId>…

数据结构实验三: 图的操作与实现

数据结构实验一:线性表,堆栈和队列实现 数据结构实验二 :二叉树的操作与实现 数据结构实验三: 图的操作与实现 数据结构实验四 : 查找和排序算法实现 文章目录一、实验目的&#xff1a;二、使用仪器、器材三、实验内容及原理1、教材P310实验题1&#xff1a;实现图的邻接矩阵和邻…

Springboot扩展点之BeanFactoryPostProcessor

Springboot扩展点之BeanFactoryPostProcessor1.功能特性BeanFactoryPostProcessor的执行是Spring Bean生命周期非常重要的一部分&#xff1b; BeanFactory级别的后置处理器&#xff0c;在Spring生命周期内&#xff0c;org.springframework.beans.factory.config.BeanFactoryPos…

【C语言】10题相关讲解+总结----有用的知识1

总结【C语言】10题&#xff0c;有兴趣的可以看看1.结构体与typedef联系2.结构体中涉及的操作符3.指针数组与数组指针4.数组首元素的作用5.喝汽水问题6.上三角矩阵判定7 矩阵相等判定8.VS调试技巧9.Debug与Release关系10.调整奇数偶数顺序11.有序序列合并1.结构体与typedef联系 …

开发互动直播应用很简单:声网 Android Demo保姆级运行教程

本文作者是来自声网开发者社区的用户“Xiaohua”。 前言 本人在参与《声网开发者漫游指南》期间&#xff0c;通过学习了解和学会跑通声网的实时互动Demo&#xff0c;但因为课程提供的demo是移动端和pc端的&#xff0c;很少接触过&#xff0c;所以只能花点时间学习一下才能运行…

如何屏蔽 iOS 软件自动更新,去除更新通知和标记

如何禁用 iPhone、iPad 软件自动更新。适用于 iOS、iPadOS 和 watchOS&#xff0c;即 iPhone、iPad 和 Apple Watch 通用。 请访问原文链接&#xff1a;https://sysin.org/blog/disable-ios-update/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&a…

WebAssembly编译之(4)-WASM编译进阶(多文件、多接口)

引言 上一节我们讲到如何用Emscripten将一个C编译陈wasm&#xff0c;并导出可供Javascirpt调用的接口&#xff0c;以及C导出类的函数接口、导出类的封装对象等。然而&#xff0c;编译的方式比较玛法&#xff0c;有没办法能更友好一点实现wasm的编译呢 WASM 相关文档&#xff1a…

【自学Docker】Docker diff命令

Docker diff命令 大纲 docker diff命令教程 docker diff 命令用于比较一个 Docker容器 不同版本提交的文件差异。该命令后面的 CONTAINER 可以是容器Id&#xff0c;或者是容器名。 docker diff命令会列出 3 种容器内文件状态变化&#xff08;A - Add, D - Delete, C - Chang…

Java-基础-3.容器

一&#xff1a;为什么会出现容器&#xff1f; 在之前的学习中&#xff0c;我们学习了变量和常量。都是一个字符或者字符串&#xff0c;数字的情况。但是在实际的生产中&#xff0c;我们一次会接受到很多类型不同&#xff0c;个数不同的数据。所以&#xff0c;为了方便我们后续…

红杉:2022企业数字化年度指南

省时查报告-专业、及时、全面的行研报告库省时查方案-专业、及时、全面的营销策划方案库【免费下载】2022年12月份热门报告盘点罗振宇2023年跨年演讲PPT原稿吴晓波2022年年终秀演讲PPT原稿2023年&#xff0c;如何科学制定年度规划&#xff1f;《底层逻辑》高清配图华为2021数字…

[基础语法] python语法之列表的基本操作

文章目录列表已发布列表的基本操作增删改查排序列表实例练习列表 已发布 python判断语句python循环语句python之列表list python 的数据格式主要有列表、字典、元组、集合。其中列表的使用最为广泛。 任何一种数据格式的使用都离不开增、删、改、查四个操作。列表除了这四个…

【Mysql第四期 运算符规则计算】

文章目录写在前面1.算数运算符2.比较运算符3.逻辑运算符4.位运算符5.运算符的优先级拓展&#xff1a;使用正则表达式查询写在前面 基本的运算符号在计算机编程领域都是相通的&#xff0c;会有自己的一些特定符号语言&#xff0c;就像是各地的普通话一样&#xff0c;尽管语音描…

剑指 Offer II 004只出现一次的数字

给你一个整数数组 nums &#xff0c;除某个元素仅出现 一次 外&#xff0c;其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 示例 1&#xff1a; 输入&#xff1a;nums [2,2,3,2] 输出&#xff1a;3 示例 2&#xff1a; 输入&#xff1a;nums [0,1,0,…

Linux中Vi编辑器和Vim编辑器

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java案例分…

Docker常用命令总结

基础命令 1.启动docker systemctl start docker 2.关闭docker systemctl stop docker 3.设置docker为自启动 systemctl enable --now docker 4.重启docker systemctl restart docker 3.查看docker版本信息 docker version 4.查看docker详细信息 docker info Clien…

Spring定时器超过30分钟问题

目前需要定时器做一个定时扫描任务的功能&#xff0c;原先都是定时在半个小时&#xff0c;程序跑起来也没事。但是最近公司要求定时时间加长到45分钟&#xff0c;而调整完配置完后发现&#xff0c;程序是在45分钟和整点进行的扫描。 下面是我做的示例时间缩短为45秒 spring。x…

守护进程编程流程及代码实现

概念不做阐述&#xff0c;本文主要内容为守护进程编程部分的知识说明 守护进程的编程流程&#xff1a; 1.fork退出父进程&#xff0c;保证留下的子进程是组员进程 2.利用setsid()创建新会话&#xff0c;把子进程挪到新的会话中 //获取会话是getsid() 3.fork退出父进程&#x…

完成基于Servlet的对user表的增删改查

基于Servlet的增删改查 1.开发环境 IDEAJDK1.8Tomcat8.5Mysql 8.0.12 2.数据库 2.1表创建 2.2表数据 3.JavaWeb代码 3.1目录结构 3.2util包下代码 JdbcUtil完成对数据库的连接和资源释放 JsonResult对返回前端资源的封装 JdbcUtil代码&#xff1a; /* 数据库连接板帮助类 …

Python中的垃圾回收机制

Python的垃圾回收主要以引用计数为主&#xff0c;分代回收为辅。引用计数在Python中&#xff0c;使用了引用计数这一技术实现内存管理。一个对象被创建完成后就有一个变量指向这个对象&#xff0c;那么就这个对象的引用计数为1&#xff0c;以后如果有其他变量指向这个对象&…

不吹牛,完爆ant design的定位组件,floating-ui来也

前言 因为要写react定位组件&#xff08;这不是标题党&#xff0c;就是完爆ant design的定位组件&#xff0c;你应该看到一半就会同意我的观点&#xff09;&#xff0c;如下图&#xff1a; 红框部分是用绝对定位放在按钮上面的&#xff0c;你们B端用的主流组件库都是这样实现的…