如何用node写qq机器人
2020-10-20 本文已影响0人
还好还好L
必要的要的模块
const cryto = require('crypto'); //配合oicq进行登录
const oicq = require("oicq"); //关键的npm包 别人封装好的qq登录
初始demo可以去看 oicq 官方文档
这里要注意的一个点就是 初次使用手机登录可能会报安全问题,建议使用手表登录,然后用返回的链接用手机认证一下。然后再重新登录就不会出现验证登录或者你账号问题了。
然后就可以写你自己的功能了。
我这里写了一个游戏群的群机器人,配合去爬取哔哩哔哩和豆瓣的数据来给群里面进行每日任务和每周复刻信息。
码云地址
主要代码预览
const express = require('express');
const router = express.Router();
const cryto = require('crypto')
const oicq = require("oicq");
const https = require('https')
const xpath = require('xpath')
const dom = require('xmldom').DOMParser
const schedule = require('node-schedule');
const zaoCi = require('./zao')
const kuaCi = require('./kua')
const defaultConfig = require('./config');
// 图片配置
const xianList =
defaultConfig.xianList
// 群配置
const qunList =
defaultConfig.qunList
// 托管的QQ号配置
const {
uin,
pwd
} =
defaultConfig.account
// defaultConfig.accountTest
// 每日任务upid
const upId =
defaultConfig.upId
// 复刻消息
let fukeTime = ''
let fukeImg = ''
// 每日任务
let imgList = []
// 运行时获取一次
// 获取每日
getImgList()
// 定时处理
scheduleCronstyle()
// 获取复刻
getAncestor()
const password_md5 = cryto.createHash('md5').update(pwd).digest('hex')
const config = {
platform: 3, //登陆类型 1手机 2平板 3手表(不支持部分群事件)
// log_level: "info", //日志级别,有trace,debug,info,warn,error,fatal,off
log_level: "off", //日志级别,有trace,debug,info,warn,error,fatal,off
kickoff: false, //被挤下线是否在3秒后反挤对方
ignore_self: true, //群聊是否无视自己的发言
}
const client = oicq.createClient(uin, config);
client.login(password_md5);
// 登录
client.on("system.login.captcha", () => {
process.stdin.once("data", input => {
client.captchaLogin(input);
});
});
// 监听信息
client.on("message", data => {
console.log(data)
console.log(data.message)
// 私聊小助手时
if (data.message_type == "private") {
setTimeout(() => {
defaultMessage(data)
}, 0)
}
if (qunList[data.group_id]) {
// @小助手时处理
if (data.message[0].type == "at" && data.message[0].data.qq == uin) {
// 处理消息
setTimeout(() => {
messageProcess(data, data.message[1].data.text)
}, 0)
}
if (qunList[data.group_id].ka) {
messagePraise(data)
return false
}
// 日常消息处理
setTimeout(() => {
defaultMessage(data)
}, 0)
}
});
client.on("request", data => console.log(data));
client.on("notice", data => console.log(data));
// 发送夸人消息
function messagePraise(data) {
client.sendGroupMsg(data.group_id, kuaCi[getRandomInt(72)])
}
// 消息处理函数
function messageProcess(data, text) {
let sex = data.sender.sex == "male" ? '靓仔' : '靓妹'
switch (text) {
case " 0":
qunList[data.group_id].ka = false
client.sendGroupMsg(data.group_id, `呜呜呜~小可爱再见呀!\n [CQ:image,cache=0,file=http://localhost:1001/images/ku.jpg]`)
break
case " 再见":
qunList[data.group_id].ka = false
client.sendGroupMsg(data.group_id, `呜呜呜~小可爱再见呀!\n [CQ:image,cache=0,file=http://localhost:1001/images/ku.jpg]`)
break
case " 安静":
qunList[data.group_id].ka = false
client.sendGroupMsg(data.group_id, `呜呜呜~小可爱再见呀!\n [CQ:image,cache=0,file=http://localhost:1001/images/ku.jpg]`)
break
case " 1":
qunList[data.group_id].ka = true
client.sendGroupMsg(data.group_id, `美好的一天美好的你,美好的话语送给你!`)
break
case " 开启夸人模式":
qunList[data.group_id].ka = true
client.sendGroupMsg(data.group_id, `美好的一天美好的你,美好的话语送给你!`)
break
case " 夸我":
qunList[data.group_id].ka = true
client.sendGroupMsg(data.group_id, `美好的一天美好的你,美好的话语送给你!`)
break
default:
client.sendGroupMsg(data.group_id, `${sex}小助手现在能为你做的事情为
1.定时任务
每日8点报每日任务(数据来源为b站up:彤鱼不吃鱼吖_),每周报最新复刻信息(数据来源于豆瓣小组(放我出赶due)的返场先祖记录贴)\n
2.聊天关键词(消息携带)
(每日任务|今日任务) 会触发小助手私聊每日任务
(近期先祖|最新复刻) 会触发小助手私聊最新复刻信息
(先祖在哪里|先祖位置) 会触发小助手私聊询问你想知道哪里先祖的位置,回答小助手会发送对应攻略
(小金人在哪里|小金人位置) 会触发小助手私聊询问你想知道哪里小金人的位置,回答小助手会发送对应攻略
(近期活动) 会触发小助手私聊发送官方微博地址
(群没有开启私聊的话请自行添加小助手)\n
3.特殊功能
@我 (1|开启夸人模式|夸我) 开启彩虹屁模式
@我 (0|再见|安静) 关闭彩虹屁模式
`)
}
}
// 处理对话
function defaultMessage(data, type) {
let text = data.message[0].data.text ? data.message[0].data.text : ''
let sex = data.sender.sex == "male" ? '靓仔' : '靓妹'
if (text.indexOf("今日任务") != -1 || text.indexOf("今天任务") != -1 || text.indexOf("每日任务") != -1) {
client.sendPrivateMsg(data.user_id, imgList + '\n以上就是今日份的小小幸运哟~')
} else if (text.indexOf("近期先祖") != -1 || text.indexOf("最新先祖") != -1 || text.indexOf("最新复刻") != -1) {
client.sendPrivateMsg(data.user_id, `近期复刻先祖消息!${fukeTime}\n [CQ:image,cache=0,file=${fukeImg}] \n数据来源于豆瓣小组(放我出赶due)的返场先祖记录贴`)
} else if (text.indexOf("近期活动") != -1) {
client.sendPrivateMsg(data.user_id, `${sex}请在官方微博查看 https://m.weibo.cn/u/6355968578#_loginLayer_1602073018866`)
} else if ((text.indexOf("先祖在哪里") != -1 || text.indexOf("先祖位置") != -1) && text.indexOf("复刻先祖") == -1) {
client.sendPrivateMsg(data.user_id, `${sex}请告诉我你想知道的先祖位置!\n 例如 晨岛`)
} else if (text.indexOf("小金人在哪里") != -1 || text.indexOf("小金人位置") != -1) {
client.sendPrivateMsg(data.user_id, `${sex}请告诉我你想知道的小金人位置! \n 例如 晨岛小金人`)
} else {
// 处理先祖位置
if (data.message_type == "private") {
if (xianList.indexOf(text) != -1) {
client.sendPrivateMsg(data.user_id, `${xianList[xianList.indexOf(text)]}位置来咯!\n [CQ:image,cache=0,file=http://localhost:1001/images/${xianList[xianList.indexOf(text)]}.jpg]`)
}
}
}
}
// 获取复刻先祖图片
function getAncestor() {
let option = {
hostname: 'www.douban.com',
path: '/group/topic/169143556/',
headers: {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cache-Control": "max-age=0",
"Connection": "keep-alive",
"Host": "www.douban.com",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36"
}
};
return new Promise(resFn => {
https.get(option, function (okdata) {
let json = ""
okdata.setEncoding("utf8")
okdata.on("data", chunk => json += chunk)
okdata.on("end", () => {
var doc = new dom().parseFromString(json)
let imgList = xpath.select("//div[@class='image-wrapper']/img/@src", doc)
let text = xpath.select("//div[@class='rich-content topic-richtext']/p/text()", doc)
imgList.forEach((v, i) => {
if (i == imgList.length - 2) {
fukeImg = v.value
}
})
text.forEach((v, i) => {
if (i == text.length - 3) {
fukeTime = v.nodeValue
}
})
resFn()
})
})
})
}
// 获取每日任务
function getImgList() {
return new Promise(resFn => {
https.get(`https://api.bilibili.com/x/space/article?mid=${upId}`, function (okdata) {
let json = ""
okdata.setEncoding("utf8")
okdata.on("data", chunk => json += chunk)
okdata.on("end", () => {
let id = JSON.parse(json).data.articles[0].id
https.get(`https://www.bilibili.com/read/cv${id}`, function (okdata) {
let datas = ""
okdata.setEncoding("utf8")
okdata.on("data", chunk => datas += chunk)
okdata.on("end", () => {
let titleList = []
var doc = new dom().parseFromString(datas)
xpath.select("//figure/figcaption/text()", doc).forEach(item => {
titleList.push(item.data)
})
let i = -1
imgList = xpath.select("//figure/img/@data-src", doc).map((item, index) => {
if (item.value.indexOf('.jpg') != -1) {
i++
return `[CQ:image,cache=0,file=https:${item.value}]\n ${titleList[i] == undefined?'这个图片我就不解释咯!':titleList[i]}`
}
}).join(" ")
resFn()
})
})
})
})
})
}
// 定时函数
function scheduleCronstyle() {
//每天早上:
schedule.scheduleJob('59 59 7 * * *', async () => {
await getImgList()
Object.keys(qunList).forEach(async (item) => {
if (!qunList[item].no) {
qunList[item].ka = false
await sendMsg(item, true)
}
});
});
//每周三发送:
schedule.scheduleJob('59 59 6 * * 3', async () => {
await getAncestor()
Object.keys(qunList).forEach(async (item) => {
await sendMsg(item)
});
});
}
// 发送定时消息
function sendMsg(item, type) {
return new Promise(resFn => {
if (type) {
client.sendGroupMsg(item, imgList + '\n' + zaoCi[getRandomInt(100)])
} else {
client.sendGroupMsg(item, `近期复刻先祖消息!${fukeTime}\n [CQ:image,cache=0,file=${fukeImg}] \n数据来源于豆瓣小组(放我出赶due)的返场先祖记录贴`)
}
resFn()
})
}
// 随机取一句话
function getRandomInt(number) {
return Math.floor(Math.random() * number)
}
/* GET users listing. */
router.get('/', function (req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
测试机器人群号 334014763