使用go-cqhttp搭建QQ机器人
- 使用go-cqhttp搭建QQ机器人
- 序言
- 安装环境
- 配置项目
- 配置config.yml(客户端信息)
- 配置device.json(账号信息)
- 消息监听
- 消息上报内容
- 监听程序
- (插入)go-cqhttp运行的原理
- 消息回复
- 代码整合
使用go-cqhttp搭建QQ机器人
序言
go-cqhttp是基于 Mirai 以及 MiraiGo 的 OneBot Golang 原生实现(此句照搬文档)
个人使用(不知道是不是只能使用)Python语言进行编写,仅供教程,不做完全分享
官方文档地址
github项目地址
安装环境
Python语言环境配置下载Python
要勾选Add python.exe to PATH
点击Next
勾选Add Python to environment variables
Install
安装完毕后Win + R打开运行输入cmd
键入Python
如上图所示即为安装成功
配置项目
下载go-cqhttp.exe后,双击运行,无视弹窗内容直接确定(因为要用运行完exe生成的bat来启动exe才是正确启动),三次确定后出现go-cqhttp.bat,双击运行。
配置config.yml(客户端信息)
选择HTTP通信,提示退出,打开config.yml
账号密码可不配置,拉到最下面
修改为以下内容
//可将从server部分完全替换
servers:
# 添加方式,同一连接方式可添加多个,具体配置说明请查看文档
#- http: # http 通信
#- ws: # 正向 Websocket
#- ws-reverse: # 反向 Websocket
#- pprof: #性能分析服务器
- http: # HTTP 通信设置
address: 0.0.0.0:5700 # HTTP监听地址
timeout: 5 # 反向 HTTP 超时时间, 单位秒,<5 时将被忽略
long-polling: # 长轮询拓展
enabled: false # 是否开启
max-queue-size: 2000 # 消息队列大小,0 表示不限制队列大小,谨慎使用
middlewares:
<<: *default # 引用默认中间件
post: # 反向HTTP POST地址列表
#- url: '' # 地址
# secret: '' # 密钥
# max-retries: 3 # 最大重试,0 时禁用
# retries-interval: 1500 # 重试时间,单位毫秒,0 时立即
url: http://127.0.0.1:5701/ # 地址
secret: '' # 密钥
max-retries: 10 # 最大重试,0 时禁用
retries-interval: 1000 # 重试时间,单位毫秒,0 时立即
这里要特别注意的是,http配置的address与下方post的url端口不能相同(可以修改)
保存后运行bat,尝试登录
[2023-01-07 00:23:26] [INFO]: 当前版本:v1.0.0-rc4
[2023-01-07 00:23:26] [INFO]: 将使用 device.json 内的设备信息运行Bot.
[2023-01-07 00:23:26] [INFO]: Bot将在5秒后登录并开始信息处理, 按 Ctrl+C 取消.
[2023-01-07 00:23:31] [INFO]: 开始尝试登录并同步消息...
[2023-01-07 00:23:31] [INFO]: 使用协议: Android Phone
[2023-01-07 00:23:32] [INFO]: Protocol -> connect to server: 36.155.206.145:8080
[2023-01-07 00:23:32] [WARNING]: Protocol -> device lock is disable. http api may fail.
[2023-01-07 00:23:35] [INFO]: 收到服务器地址更新通知, 将在下一次重连时应用.
[2023-01-07 00:23:35] [INFO]: 登录成功 欢迎使用: acao
[2023-01-07 00:23:35] [INFO]: 开始加载好友列表...
[2023-01-07 00:23:35] [INFO]: 共加载 23 个好友.
[2023-01-07 00:23:35] [INFO]: 开始加载群列表...
[2023-01-07 00:23:36] [INFO]: 共加载 7 个群.
[2023-01-07 00:23:36] [INFO]: 资源初始化完成, 开始处理信息.
[2023-01-07 00:23:36] [INFO]: アトリは、高性能ですから!
[2023-01-07 00:23:36] [INFO]: HTTP POST上报器已启动: http://127.0.0.1:5701/
[2023-01-07 00:23:36] [INFO]: 正在检查更新.
[2023-01-07 00:23:36] [INFO]: CQ HTTP 服务器已启动: [::]:5700
[2023-01-07 00:23:48] [INFO]: 检查更新完成. 当前已运行最新版本.
[2023-01-07 00:23:48] [INFO]: 开始诊断网络情况
[2023-01-07 00:23:51] [INFO]: 网络诊断完成. 未发现问题
[2023-01-07 00:23:58] [WARNING]: 上报 Event 数据到 http://127.0.0.1:5701/ 失败: Post "http://127.0.0.1:5701/": dial tcp 127.0.0.1:5701: connectex: No connection could be made because the target machine actively refused it. 将进行第 1 次重试
[2023-01-07 00:24:02] [WARNING]: 上报 Event 数据到 http://127.0.0.1:5701/ 失败: Post "http://127.0.0.1:5701/": dial tcp 127.0.0.1:5701: connectex: No connection could be made because the target machine actively refused it. 将进行第 2 次重试
这里上报出现了许多错误,是正常现象,因为我们没有监听程序,没地方上报
等我们接下来写完监听程序就不会这样了
注:第七行的[WARNING]: Protocol -> device lock is disable. http api may fail.
属于正常现象,不需要找问题(不影响)
在 config.yml 中,还可以设置在线状态,参考在线状态
配置device.json(账号信息)
{
"display": "MIRAI.619943.001",
"product": "mirai",
"device": "mirai",
"board": "mirai",
"model": "mirai",
"finger_print": "mamoe/mirai/mirai:10/MIRAI.200122.001/0642953:user/release-keys",
"boot_id": "8cfd480f-5acb-cb0f-0462-9dd269b378c3",
"proc_version": "Linux version 3.0.31-MJXB114B (android-build@xxx.xxx.xxx.xxx.com)",
"protocol": 1,
"imei": "121268379926671",
"brand": "mamoe",
"bootloader": "unknown",
"base_band": "",
"version": {
"incremental": "5891938",
"release": "10",
"codename": "REL",
"sdk": 29
},
"sim_info": "T-Mobile",
"os_type": "android",
"mac_address": "00:50:56:C0:00:08",
"ip_address": [10, 0, 1, 3],
"wifi_bssid": "00:50:56:C0:00:08",
"wifi_ssid": "\u003cunknown ssid\u003e",
"imsi_md5": "90b7592b208260238577eb697e1f426b",
"android_id": "49ebbf42888f6b36",
"apn": "wifi",
"vendor_name": "MIUI",
"vendor_os_name": "mirai"
}
这是格式化过的!!!不是你的出了问题!!!
主要注意的是Protocol,这是你的登录状态,默认5位ipad协议,这里我改用了Android协议
Android协议:登录状态显示,前面config.yml有设置的,但是手机端无法再登录Bot的QQ
ipad协议优点:运行Bot后可在手机端登录,但是登录状态会显示为WiFi在线-2G
值得一提的是,在config.yml的38行,有一个是否上报自身消息,也就是所谓的自触发,以及40行的是否移除replay自带at效果,根据自身需要打开(False是关闭,True是打开)
消息监听
消息上报内容
也就是我们要从go-cqhttp那里接收上报的消息了
先来了解一下监听上报的消息格式内容(普通消息)
{
'post_type': 'message',
'message_type': 'group',
'time': 1672415467,
'self_id': 3054770279,
'sub_type': 'normal',
'font': 0,
'group_id': 594875964,
'user_id': 423866219,
'message_id': -731133797,
'sender': {
'age': 0,
'area': '',
'card': '',
'level': '',
'nickname': '福建第一深情',
'role': 'owner',
'sex': 'unknown',
'title': '',
'user_id': 423866219
},
'anonymous': None,
'message': '6',
'message_seq': 4452,
'raw_message': '6'
}
这是一条消息(当然也是格式化之后的)
其中post_type是我们接收到的消息类型,即message
message_type是指我们接收到的是group(群聊消息)或是private(私聊消息)
group_id为群号,user_id为QQ号,self_id为Bot本身的QQ号
那我们开始写一个监听程序
监听程序
我们用的是Python的pip库中的Flask,Win+R打开运行输入cmd后点击确定,先更新一下pip
C:\User\afanm> python -m pip install --upgrade pip
更新完成后再安装Flask
C:\User\afanm> pip install flask
将flask替换成其它,再安装requests
打开一个.py文件随意命名(我这里叫main.py)
监听如下
from flask import Flask,request
import afan
app = Flask(__name__)
@app.route('/', methods=["POST"])
def post_data():
data = request.get_json()
print(data)
if data['post_type'] == 'message':
message = data['message']
print(message)
afan.messagex()
elif data['post_type'] == 'notice':
pass
else:
print("忽略上报")
return "OK"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5701)
导入初始化Flask,我们将request得到的数据赋值给data,意思就是data这个变量就是我们收到上报的消息,并调用我们写在afan.py的回复,这里的port就是我们刚刚post设置的端口
(插入)go-cqhttp运行的原理
go-cqhttp客户端将我们电脑配置成为微型服务器,开放了5700和5701端口进行通讯,通过访问我们自己电脑上的API接口进行发送,所以即使没有程序,我们访问接口依旧可以运行
例如发送消息接口终结点为send_msg,在运行客户端后,网址访问127.0.0.1/send_msg依旧可以发送消息(需要提交参数)
消息回复
那么我们封装一个接口,直接调用就可以发送消息,不需要反复写API
由官方API文档,我们能了解到:
消息的终结点为send_msg
需要的参数为群号,消息内容,发送类型,我们以群消息为例
class API:
@staticmethod
def send(message):
url = "http://127.0.0.1:5700/send_msg"#这里要加上http://,不然会报错
data = request.get_json()#获取上报消息
params = {
"message_type":data['message_type'],
"group_id":data['group_id'],
"message":message
}
requests.get(url,params=params)
这样,当我们在后方词库调用该函数时,只需传入消息内容便可以发送了,私聊的话只需要判断消息来源进行微调即可
接下来,创建文件afan.py,导入main.py以及一些其它库
我们前面写道,如果消息类型为message的话,调用afan.messagex(),导入afan后,定义一个函数messagex()
我的Bot名为阿草,我先写一个当我发送 阿草 时回复 阿草在哦 的词库
import requests
from flask import Flask,request
from main import API
def messagex():
data = request.get_json()
message = data['message']
if "阿草" == message:
API.send("阿草在哦")
else:
print("指令错误")#这里不是发送,是打印到我们后台监听程序
这样,当消息为阿草的时候,调用API发送阿草在哦
接下来我们只要运行main.py,然后启动go-cq客户端就可以了
至于其它东西,我们只需要根据上报收到的消息进行设置就行了,上报消息内容,我们依然可以在文档的 Event上报 处查看
实现其它内容,只需要封装其它接口进行调用即可
注意:封装接口时调用的端口是5700,客户端监听5700,消息post上报到5701,再有main.py进行监听5701调用词库回复,可根据需要自行修改,不要运行afan.py词库文件,会造成端口冲突的,我们只需要运行main.py和go-cq客户端即可
代码整合
最后送上上面整合的监听以及回复代码
main.py
from flask import Flask,request
import requests
import afan
app = Flask(__name__)
class API:
@staticmethod
def send(message):
url = "http://127.0.0.1:5700/send_msg"#这里要加上http://,不然会报错
data = request.get_json()#获取上报消息
params = {
"message_type":data['message_type'],
"group_id":data['group_id'],
"message":message
}
requests.get(url,params=params)
@app.route('/', methods=["POST"])
def post_data():
data = request.get_json()
print(data)
if data['post_type'] == 'message':
message = data['message']
print(message)
afan.messagex()
else:
print("忽略消息")
return "OK"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5701)
afan.py
import requests
from flask import Flask,request
from main import API
def messagex():
data = request.get_json()
message = data['message']
if "阿草" == message:
API.send("阿草在哦")
else:
print("指令错误")#这里不是发送,是打印到我们后台监听程序
文章出处登录后可见!