使用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("指令错误")#这里不是发送,是打印到我们后台监听程序