需求介绍
最近有一个朋友天天蹲点看七海娜娜米的直播,身为友達的我实在是看不下去了,本着闲着没事干不如找点乐子玩的人生态度突然想整一个 QQ 机器人来通知海子姐的直播动态,一开播就把消息推送到群里,方便朋友及时上线充钱送礼
本文特点
本文主要用于简单介绍 QQ 机器人的搭建,所以一切从简,主要讲基本原理及实现功能,如果想深入了解请阅览官方文档
文章面向群体:零基础群体
、不想看官方文档患者
、图个乐读者
、脆脆鲨
如果你也是受众群体之一的话,那就开始吧!!!
敲代码主要需要两个东西:
本次所使用的代码都是基于 node 环境开发, 因此必须需要安装 node 环境,node下载地址
当然如果你不想用宇宙无敌超好用的 vscode 敲代码的话,用记事本也不是不行,vscode下载地址
下载完 node 环境后在终端输入 npm 应有如下信息(或者说只要不是找不到该命令就成功)
如果有问题请参考: 如何配置 node 环境
注意:QQ 机器人被风控的风险,因此千万不要用自己用的 QQ 充当机器人,请新注册一个小号
首先我们需要一个工具来登入 QQ,这个工具既可以拿到我们 QQ 上的所有聊天信息,又能把这些信息输出到其他地方,甚至能控制我们的 QQ 发送指定信息,那么哪里有那么好用的工具呢???
这就不得不说大名鼎鼎的 go-cqhttp 了,使用它可以很方便地接入 QQ 并开启数据通信服务,可以理解为我们登入了一个没有操作界面的 QQ
首先我们需要进行下载,下载地址,请根据自己的操作系统来选择下载包,如果访问失败则请科学上网
下面我以 window 系统为例,下载完后直接启动应用,可能会出现终端提示你需要连接哪种服务,这里可以多选,但是选择 2
选用正向 websocket 服务即可,它会自动在当前目录下生成默认配置文件 config.yml
如果你是 mac 用户,那么生成的配置文件会放到用户的home目录下
下面简单介绍下配置信息:
首先是需要填登入的信息,这里只需要填入 QQ 号和密码(这里以 123456 为例),再次启动应用程序就可以实现登入 QQ 了
# config.yml
account: # 账号相关
uin: 123456 # QQ账号
password: '123456' # 密码为空时使用扫码登录
encrypt: false # 是否开启密码加密
status: 0 # 在线状态 请参考 https://docs.go-cqhttp.org/guide/config.html#在线状态
relogin: # 重连设置
delay: 3 # 首次重连延迟, 单位秒
interval: 3 # 重连间隔
max-times: 0 # 最大重连次数, 0为无限制
# 是否使用服务器下发的新地址进行重连
# 注意, 此设置可能导致在海外服务器上连接情况更差
use-sso-address: true
然后是开启的服务信息,需要记住开启的 websocket 服务地址,这里表示会用本机充当服务器,开启服务端口为 6700
# 连接服务列表
servers:
- ws:
# 正向WS服务器监听地址
host: 127.0.0.1
# 正向WS服务器监听端口
port: 6700
middlewares:
<<: *default # 引用默认中间件
实际上就是输入个要充当机器人的账号和密码就完事儿了,其他配置默认不动,如果感兴趣的可以看一下 官方配置信息,本文的原则是:能凑合用就行
如果成功启动,会看到如下信息
此时如果你使用该 QQ 发言或收到消息,会在该终端中看到,没错,go-cqhttp 服务可以监听到该用户的所有行为
注意:请保持该服务,不要关闭终端
我们已经能实现登入 QQ 拿到用户行为信息了,那么现在我们还需要使用一个东西来控制我们的这个 QQ 用户去做一些我们想要做的事情,即要把它变成一个机器人
现在已经有不少成熟的聊天机器人框架了,这次我选用的是 koishi,原因:
首先新建一个目录,我这里起名为 koishi-robot
打开该目录路径终端,依次输入(这里请确保你之前已经安装好 node 环境)
npm init -y
npm install koishi koishi-adapter-onebot koishi-plugin-common
首先我们需要先配置 QQ 信息和 服务信息,在 koishi-robot
文件夹下新建文件 config.js
并输入
// koishi-robot/config.js
module.exports = {
// Koishi 服务器监听的端口
port: 8080,
onebot: {
path: '',
secret: '',
},
bots: [{
type: 'onebot:ws',
server: 'http://localhost:6700',
selfId: '这里填写QQ号',
token: '这里填写QQ密码',
}],
plugins: {
'common': {}
},
}
注意:server 需要和 go-cqhttp 开启的服务地址一致,可以看到上面 server 的配置信息就是我们之前 go-cqhttp 地址和端口
下面需要生成机器人控制服务,在 koishi-robot
文件夹下新建文件 app.js
并输入
// koishi-robot/app.js
const { App } = require('koishi')
const config = require('./koishi.config')
require('koishi-adapter-onebot')
// 注入配置
const app = new App({
...config
})
// 注册插件
app.plugin(require('koishi-plugin-common'))
app.start()
下面就是启动我们的服务,在 koishi-robot
路径下的终端输入
node app.js
如果成功会看到如下输出信息:
此时我们已经成功启动了控制 QQ 机器人的服务,刚才引入的 koishi-plugin-common
插件已经内置了一些基本功能,可以尝试使用 echo
命令让我们的机器人回复指定消息
这样,我们就基本上弄出一个 QQ 机器人了,可以使用下面模型简单理解我们刚才所做的事情
koishi 主要是以插件的形式来控制我们的机器人行为,即编写了一套逻辑之后,在服务里去配置使用这套逻辑
首先为了开发方便调试,这里我们先下一个 nodemon
包,来让我们的服务可以实现热更新:即修改代码即时更新服务,不需要手动重新启动,项目路径终端输入
npm install nodemon
然后修改我们目录下的 package.json
中添加项目启动命令,此时我的文件内容为:
{
"name": "koishi-robot",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "nodemon ./src/app.js"
},
"dependencies": {
"koishi": "^3.14.2",
"koishi-adapter-onebot": "^3.1.0",
"koishi-plugin-common": "^4.3.5",
"nodemon": "^2.0.13"
}
}
接下来尝试启动服务,项目路径终端输入
npm run start
下面简单介绍插件的写法,在项目目录下新建文件 plugin.js
// koishi-robot/plugin.js
function apply(ctx) {
}
module.exports = {
name: 'plugin-my-plugin',
apply
}
然后需要在服务中引用这个插件
// index.js
// ...其他代码
app.plugin(require('./plugin'))
最后在配置文件中也配置一下(这里实操感觉不配也能用,但是官网写着要配,那还是应该对官方文档要有敬畏之心)
键名为插件的路径,比如这里的
.plugin
就是对应我们的plugin.js
文件
// koishi-robot/config.js
module.exports = {
// ...其他配置
plugins: {
'./plugin': true, // true 和 {} 的效果等价
},
}
现在我们就已经导入插件了,接下来可以给插件编写功能,先介绍一下中间件的写法
// koishi-robot/plugin.js
function apply(ctx) {
ctx.middleware((session, next) => {
// 这里机器人收到信息后该做的行为
return next()
})
}
机器人收到任意信息都会触发中间件,我们可以在这里设置机器人接受到任意信息后该做什么,可以先看一下接受到消息后我们拿到了什么数据,下图为 session 中的内容
为了更加生动的表现,这里不惜曝光自己两个小号信息,下面是使用 850300443 咯咯哒
作为机器人载体,2536671541 秋刀鱼
作为触发机器人的发言用户,分别在私聊和群聊 56546216
中发言,拿到的 session 信息
可以看出此时已经可以很方便的获取到下面主要信息:
比如我们可以很容易的写出一个功能:在群里发现指定的用户发言时,机器人就发送一段话
function apply(ctx) {
ctx.middleware((session, next) => {
// 如果监测到qq号为2536671541的用户发言,发送指定语句
if(session.userId === '2536671541') {
session.send('监听到指定用户发言')
}
return next()
})
}
session.send( ) 用于在机器人收到消息后,发送指定内容到对应渠道中,即监听到消息就会在对应的群或私聊进行回复,一般需要加入判断语句,否则任意一条发言(无论什么渠道)都会进行回复
有时候,我们希望能通过指令来触发机器人的操作,就比如最开始的 echo
操作,这时候需要指令操作
function apply(ctx) {
ctx
.command('live', '查询海子姐开播状态')
.shortcut('海子姐开播了吗')
.action(({ session }) => {
session.send('收到指令 海子姐开播了吗')
})
}
command:声明一个指令及其帮助描述
shortcut:指令别名,可以使用中文触发指令
action:接收到指令后做的操作
现在我们已经知道了接收到消息后机器人才会发送消息,那么有什么方法可以直接控制机器人发送消息到指定渠道呢,下面介绍广播的基本写法
function apply(ctx) {
ctx.broadcast(
['onebot:private:123456', 'onebot:group:654321'],
'发送的消息'
)
}
上面的代码功能:手动将信息“发送的信息”,发送到 qq 号为 123456 的用户和 qq 群号为 654321 的 qq 群中
onbot 表示的是一个平台,因为 koishi 不仅可以接入 qq 还可以接入其他平台,onebot 表示的是 qq 平台
有时候我们希望机器人不仅只做普通的发言,那么我们可以使用消息段来丰富我们的机器人行为,它的原理是使用 CQcode
让 QQ 知道一个用户的操作,由于接入 QQ 使用的是 go-cqhttp
,因此在 koishi 中消息段完全对应该框架, CQcode参考
比如我们希望机器人戳一戳谁,那么可以这样写
const { segment } = require('koishi')
function apply(ctx) {
ctx
.command('live', '查询海子姐开播状态')
.shortcut('海子姐开播了吗')
.action(({ session }) => {
return segment('poke', {qq: 123456})
})
}
上面代码功能:收到指令后戳一戳指定用户 123456,segment 的传参完全参照 CQcode
基本功能差不多介绍完了,还有多的下面边写边介绍吧,实际上根据上面的知识,这时候你应该已经差不多能打造一个想要的机器人功能了,下面开始进入正式动工环节,打造一个直接正式进入海子姐直播通知机器人 Time
下面写法主要
抄借鉴社区插件写法:koishi-plugin-blive ,一款用于 b 站直播的插件
基本原理很简单,海子姐在 b 站直播,那就请求 b 站的直播相关接口,拿到海子姐的直播间信息
首先根据神秘力量我们拿到 b 站直播间的请求接口,请求内容和返回内容如图:
请求地址后面跟的 id 值为 b 站直播间房间号,比如海子姐的房间号为 21452505
返回内容可以拿到直播间的相关信息,这里我们主要关注 live_status
字段,值的含义如下
然后我们需要在代码中主动请求这个接口,这里发送请求我选的是 axios
包,因此你需要在项目中下载
npm install axios
然后在我们的插件中去使用,这里本着一切从简的原则,就不把代码写的优雅和考虑复用封装了,一切为了海子姐服务!!!
const axios = require('axios')
async function apply(ctx) {
const { data } = await axios.get(
'https://api.live.bilibili.com/room/v1/Room/room_init',
{
params: { id: 21452505 },
headers: {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0'
}
}
)
const liveStatus = {
'0': '未开播',
'1': '直播中',
'2': '轮播中'
}[data.live_status]
ctx.broadcast(
['onebot:group:123456'],
`海子姐直播状态:${liveStatus}`
)
}
上面代码的功能:请求获取到了海子姐的直播间状态后,发送信息到 qq 群 123456 中
我们需要的是海子姐一开播我们就立马获取到信息,上面的代码明显不符合要求,因此我们需要的是,每一分钟都请求一遍接口,监听到海子姐的直播间状态发生变化时,才把消息推送到群里,因此我们可以换成下面的写法
const axios = require('axios')
let preStatus = 0 // 存储上一次请求的直播间状态
let statusSwitch = false // 用于存储和上一次请求相比直播间状态是否发生变化
function apply(ctx) {
// koishi接入go-cqhttp服务时会触发下面代码
ctx.on('connect', () => {
setInterval(async () => {
const { data } = await axios.get(
'https://api.live.bilibili.com/room/v1/Room/room_init',
{
params: { id: 21452505 },
headers: {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0'
}
}
)
if(preStatus !== data.live_status) {
statusSwitch = true
preStatus = data.live_status
} else {
statusSwitch = false
}
// 如果直播状态变更,就朝指定QQ群发送信息
if(statusSwitch) {
const message = preStatus ? '海子姐下播啦' : '海子姐开播啦'
ctx.broadcast(
['onebot:group:123456'],
message
)
}
}, 60 * 1000) // 60秒重复执行一次
})
}
上面代码的功能是:每一分钟请求一次直播间信息,一旦直播状态发生变化,就发送推送消息到qq群中,注意重复的时间不要太短,不要可能高频请求接口会被 b 站限制请求(不要问我怎么知道的)
注意:xml为黑科技,多次发送会导致qq号被风控,导致无法正常发送xml,这里只是做简单介绍,具体实现与否可以用新开小号尝试
现在我们一个简单的海子姐直播推送机器人就完成功能了,但是在发言上还是有些欠缺,只发送一段文本一点都不优雅,因此我们引入了 QQxml 来实现发送 QQ 卡片功能
koishi 可以通过 QQcode
去发送一段 xml 代码,这段 xml 会被 QQ 内部解析,然后变成特定的消息效果,如 QQ 的卡片信息
因为 我也不是很懂 有风险,因此这里只介绍 xml 的两个模板和具体效果,看个乐就行
xml 代码需要有专门的头部声明,如下所示
QQ 卡片使用
标签进行包裹内容
<msg serviceID="1" templateID="1" action="web" brief="点击进入直播间" sourceMsgId="0" url="https://live.bilibili.com/21452505?spm_id_from=333.999.0.0" flag="0" adverSign="0" multiMsgFlag="0">
msg>
brief:在聊天框外看到的预览信息
url:点击卡片进行跳转
其他的不知道什么效果~
以下是试出来的两种 xml 卡片的模板,其他的配置尝试感觉有点问题
<msg serviceID="1" templateID="1" action="web" brief="点击进入直播间" sourceMsgId="0" url="https://live.bilibili.com/21452505?spm_id_from=333.999.0.0" flag="0" adverSign="0" multiMsgFlag="0">
<item layout="6" advertiser_id="0" aid="0">
<picture cover="http://gchat.qpic.cn/gchatpic_new/0/530077417-0-094758B3DD39603D0E8563D47959D8E7/0" w="0" h="0" />
item>
<item layout="6" advertiser_id="0" aid="0">
<title>海子姐直播间title>
<summary>直播状态:${liveStatus}${liveStartTime}${liveTime}summary>
item>
<source name="哔哩哔哩" icon="http://gchat.qpic.cn/gchatpic_new/0/530077417-0-01006648643525F8630A9A97C5959700/0" action="" appid="-1" />
msg>
<msg serviceID="1" templateID="1" action="web" brief="点击进入直播间" sourceMsgId="0" url="https://live.bilibili.com/21452505?spm_id_from=333.999.0.0" flag="0" adverSign="0" multiMsgFlag="0">
<item layout="2" advertiser_id="0" aid="0">
<picture cover="http://gchat.qpic.cn/gchatpic_new/0/530077417-0-094758B3DD39603D0E8563D47959D8E7/0" w="0" h="0" />
<title>海子姐直播间title>
<summary>直播状态:${liveStatus}${liveStartTime}${liveTime}summary>
item>
<source name="哔哩哔哩" icon="http://gchat.qpic.cn/gchatpic_new/0/530077417-0-01006648643525F8630A9A97C5959700/0" action="" appid="-1" />
msg>
相比各位已经注意到了我这里的图片地址并不是网络上随便一张图的地址,这是 QQ 内部的图床,直接使用网络的图片在手机上可以正常显示在卡片中,但是在 PC 端则会裂掉
这是因为 PC 卡片引用用的是 QQ 自己的图床内的图,如果真的十分想 PC 上也正常显示的话可以如下操作:
http://gchat.qpic.cn/gchatpic_new/0/530077417-0-<把md5值填在这,不需要尖括号>/0
,这步相当于把该图存到了 QQ 内部中到目前为止已经实现了我们想要的功能,相信即使你不是一位脆脆鲨也能了解到了如何制作一个自己想要的机器人方法
目前还有一个问题,就是现在我们使用的是自己的电脑充当服务器,那就意味着我们想要我们的机器人全天工作就必须得一直开着电脑,这是不现实的,那么我们就需要自己去购买一台服务器,然后把我们的项目传到服务器中,并且在服务器上运行项目
服务器的选择有很多,比如阿里云、腾讯云等,如果你都已经决心要弄花钱弄服务器的话,那相信你一定可以去百度搜索出来如何购买服务器并部署项目,这里就不介绍了