本文最后更新于 将近 4 年前,文中所描述的信息可能已发生改变。
由于我本人已经从 NoneBot1.8.1 升级到了 NoneBot2,本系列文章之后的所提到的 NoneBot 均指代 NoneBot2。本文中 NoneBot 的配置仅适用于 NoneBot2 之前的版本,如需配置 NoneBot2 请阅读 官方文档,我有空再回来修改本文。
前言
在诈尸回归·搬迁事宜·年终总结·展望未来这篇文章里我提起过,在今年年初时我曾在溯洄的 Dice3 的基础上改写自己的掷骰机器人。我把这个机器人称作 Dr.Sink
,即陈末的谐音(沉没)的英文。可惜直到八月时酷 Q 因为不可抗力停止服务时,我还是没有实现自己最开始立下的 TO DO List。这时我的面前有两个选择,更换 Dr.sink 到 Mirai 上运行或者停止运行。一开始我当然是选择要延续 Dr.Sink 的生命,可惜当时 MiraiNative 对于酷 Q 原生插件的兼容性还是有些问题~~(当然也可能是我的问题,毕竟 Java 白痴)~~,诸多功能都出现了大大小小的 bug。由于我对 Java 不甚了解也无法 Debug,于是便放弃了 Dr.sink
的开发,结束了它短短八个月的服役。
愿我们在更开放的平行世界相遇。——酷 Q 官网
不过到了年底,有些事情迎来了转机。在酷 Q 全面崩盘之后,很多大佬投入到 Mirai 的开发中,原 CQHTTP 插件也被大佬们做出了兼容各种语言的 SDK,我这个除了 python 和 Cpp 什么也不会的废物就此找到了新的出路:使用 go-cqhttp 作为中间层,用 python 编写机器人的逻辑,也就是 nonebot 框架的基本原理。
之所以选择 NoneBot 作为机器人的框架,原因其实很简单,就是懒。有现成的框架不用,再去重复造轮子那岂不是____。~~(哦,原来我之前写 auto_video 的时候就重复造了很多轮子啊,那没事了)~~所以接下来就是讲述我学习和使用 nonebot 框架的经历了。
go-cqhttp
正如上文所说,在我下定决心放弃 Cpp 而使用 python 来开发机器人之后,我的面前就只剩下一个选择了:采用 cqhttp 作为兼容层(什么?你说 python-Mirai?很遗憾,python-Mirai 也基于 Mirai-Http-api 运行,绕了一大圈还是绕回了这一层,更蛋疼的是 Mirai-Http 和 cqhttp 还有一定的差别,更何况这个 python-Mirai 本身已经十个月没有更新了)。前面也提到了,我对于 Java 是一窍不通,MiraiConsole 简直就是我的噩梦,我更倾向于 Mirai-Go,于是最后我选择了 go-cqhttp 这个集成了 Mirai-Go 的符合 OneBot 标准的项目。
既然确定了要使用的项目,就开始行动吧。
从 release 界面下载最新版本的 go-cqhttp 并解压运行。
[WARNING]: 尝试加载配置文件 config.hjson 失败: 文件不存在
[INFO]: 默认配置文件已生成,请编辑 config.hjson 后重启程序.
第一次运行将会出现上面的提示,这时在文件夹里便会生成如下的 config.hjson
文件。
{
uin: 0
password: ""
encrypt_password: false
password_encrypted: ""
enable_db: true
access_token: ""
relogin: {
enabled: true
relogin_delay: 3
max_relogin_times: 0
}
_rate_limit: {
enabled: false
frequency: 1
bucket_size: 1
}
ignore_invalid_cqcode: false
force_fragmented: false
heartbeat_interval: 0
http_config: {
enabled: true
host: 0.0.0.0
port: 5700
timeout: 0
post_urls: {}
}
ws_config: {
enabled: true
host: 0.0.0.0
port: 6700
}
ws_reverse_servers: [
{
enabled: false
reverse_url: ws://you_websocket_universal.server
reverse_api_url: ws://you_websocket_api.server
reverse_event_url: ws://you_websocket_event.server
reverse_reconnect_interval: 3000
}
]
post_message_format: string
use_sso_address: false
debug: false
log_level: ""
web_ui: {
enabled: true
host: 127.0.0.1
web_ui_port: 9999
web_input: false
}
}
此处我们需要注意的有 uin
、password
,即机器人的 QQ 账号、密码。
顺便一提,这个 encrypt_password
虽然能帮你加密密码,但是这样你每打开一次都要输入第一次设置的 KEY,只能给开发徒增烦恼。
再顺便一提,虽然 go-cqhttp 的文档里有个 Windows 懒人法,但实际上你之后还是要自己编辑 config.hjson
,所以我一点也不推荐。
然后我们便重启 go-cqhttp,如果登录成功的话应该会出现如下信息:
[2020-12-31 19:09:34] [INFO]: 当前版本:v0.9.36-fix3
[2020-12-31 19:09:34] [INFO]: 用户交流群: 721829413
[2020-12-31 19:09:34] [INFO]: 将使用 device.json 内的设备信息运行Bot.
[2020-12-31 19:09:34] [INFO]: 开始尝试登录并同步消息...
[2020-12-31 19:09:34] [INFO]: 使用协议: iPad
[2020-12-31 19:09:34] [INFO]: Protocol -> connect to server: 120.232.18.55:8080
[2020-12-31 19:09:34] [INFO]: Admin API 服务器已启动: 127.0.0.1:9999
[2020-12-31 19:09:35] [ERROR]: Protocol -> unknown group msg: 0
[2020-12-31 19:09:35] [INFO]: 登录成功 欢迎使用: Dr.Sink
如此一来,go-cqhttp 方面的准备工作就做完了,接下来就是 nonebot 的事情了。
nonebot
NoneBot 是一个基于 OneBot 标准(原 CQHTTP)的 Python 异步 QQ 机器人框架,它会对 QQ 机器人收到的消息进行解析和处理,并以插件化的形式,分发给消息所对应的命令处理器和自然语言处理器,来完成具体的功能。
除了起到解析消息的作用,NoneBot 还为插件提供了大量实用的预设操作和权限控制机制,尤其对于命令处理器,它更是提供了完善且易用的会话机制和内部调用机制,以分别适应命令的连续交互和插件内部功能复用等需求。
NoneBot 在其底层与 OneBot 实现交互的部分使用 aiocqhttp 库,后者在 Quart 的基础上封装了与 OneBot 实现的网络交互。
得益于 Python 的 asyncio 机制,NoneBot 处理消息的吞吐量有了很大的保障,再配合 OneBot 标准的 WebSocket 通信方式(也是最建议的通信方式),NoneBot 的性能可以达到 HTTP 通信方式的两倍以上,相较于传统同步 I/O 的 HTTP 通信,更是有质的飞跃。
需要注意的是,NoneBot 仅支持 Python 3.7+。
首先我们得安装 nonebot 库。
pip install nonebot
当然我们也可以选择将源代码 clone 到本地再进行安装,此方法安装的一定是最新版本。
git clone https://github.com/nonebot/nonebot.git
cd nonebot
python setup.py install
接着新建一个 py 文件,例如我这里就新建 bot.py
。
import nonebot
if __name__ == '__main__':
nonebot.init()
nonebot.load_builtin_plugins()
nonebot.run(host='127.0.0.1', port=8080)
这时如果你直接运行 bot.py
,你可能会得到这样的结果:
ujson module not found, using json
msgpack not installed, MsgPackSerializer unavailable
[2020-03-16 15:50:26,166 nonebot] INFO: Succeeded to import "nonebot.plugins.base"
[2020-03-16 15:50:26,166 nonebot] INFO: Running on 127.0.0.1:8080
Running on http://127.0.0.1:8080 (CTRL + C to quit)
[2020-03-16 15:50:26,177] Running on 127.0.0.1:8080 over http (CTRL + C to quit)
......
OSError: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试。
这是因为我们还没有在 go-cqhttp 里开启反向 ws。
现在我们打开之前的 config.hjson
文件,找到这几行。
ws_reverse_servers: [
{
enabled: false
reverse_url: ws://you_websocket_universal.server
reverse_api_url: ws://you_websocket_api.server
reverse_event_url: ws://you_websocket_event.server
reverse_reconnect_interval: 3000
}
]
将 false
改为 true
,把下面三个参数也就是 reverse_url
,reverse_api_url
,reverse_event_url
的值都改为 ws://127.0.0.1:8080/ws/
,重新启动 go-cqhttp,我们便会在 bot.py 运行后的界面找到类似下面的一行信息:
[2020-12-31 19:29:12,835] 127.0.0.1:9005 GET /ws/ 1.1 101 - 7872
这时候打开 QQ,给你的机器人发送:
/echo 你好,世界
这意味这我们成功运行了 NoneBot 的最小实例,打开了新世界的大门。