必要的要的模塊
const cryto = require('crypto'); //配合oicq進(jìn)行登錄
const oicq = require("oicq"); //關(guān)鍵的npm包 別人封裝好的qq登錄
初始demo可以去看 oicq 官方文檔
這里要注意的一個(gè)點(diǎn)就是 初次使用手機(jī)登錄可能會(huì)報(bào)安全問題,建議使用手表登錄,然后用返回的鏈接用手機(jī)認(rèn)證一下。然后再重新登錄就不會(huì)出現(xiàn)驗(yàn)證登錄或者你賬號(hào)問題了。
然后就可以寫你自己的功能了。
我這里寫了一個(gè)游戲群的群機(jī)器人,配合去爬取嗶哩嗶哩和豆瓣的數(shù)據(jù)來給群里面進(jìn)行每日任務(wù)和每周復(fù)刻信息。
碼云地址
主要代碼預(yù)覽
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號(hào)配置
const {
uin,
pwd
} =
defaultConfig.account
// defaultConfig.accountTest
// 每日任務(wù)upid
const upId =
defaultConfig.upId
// 復(fù)刻消息
let fukeTime = ''
let fukeImg = ''
// 每日任務(wù)
let imgList = []
// 運(yùn)行時(shí)獲取一次
// 獲取每日
getImgList()
// 定時(shí)處理
scheduleCronstyle()
// 獲取復(fù)刻
getAncestor()
const password_md5 = cryto.createHash('md5').update(pwd).digest('hex')
const config = {
platform: 3, //登陸類型 1手機(jī) 2平板 3手表(不支持部分群事件)
// log_level: "info", //日志級(jí)別,有trace,debug,info,warn,error,fatal,off
log_level: "off", //日志級(jí)別,有trace,debug,info,warn,error,fatal,off
kickoff: false, //被擠下線是否在3秒后反擠對(duì)方
ignore_self: true, //群聊是否無(wú)視自己的發(fā)言
}
const client = oicq.createClient(uin, config);
client.login(password_md5);
// 登錄
client.on("system.login.captcha", () => {
process.stdin.once("data", input => {
client.captchaLogin(input);
});
});
// 監(jiān)聽信息
client.on("message", data => {
console.log(data)
console.log(data.message)
// 私聊小助手時(shí)
if (data.message_type == "private") {
setTimeout(() => {
defaultMessage(data)
}, 0)
}
if (qunList[data.group_id]) {
// @小助手時(shí)處理
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));
// 發(fā)送夸人消息
function messagePraise(data) {
client.sendGroupMsg(data.group_id, kuaCi[getRandomInt(72)])
}
// 消息處理函數(shù)
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, `美好的一天美好的你,美好的話語(yǔ)送給你!`)
break
case " 開啟夸人模式":
qunList[data.group_id].ka = true
client.sendGroupMsg(data.group_id, `美好的一天美好的你,美好的話語(yǔ)送給你!`)
break
case " 夸我":
qunList[data.group_id].ka = true
client.sendGroupMsg(data.group_id, `美好的一天美好的你,美好的話語(yǔ)送給你!`)
break
default:
client.sendGroupMsg(data.group_id, `${sex}小助手現(xiàn)在能為你做的事情為
1.定時(shí)任務(wù)
每日8點(diǎn)報(bào)每日任務(wù)(數(shù)據(jù)來源為b站up:彤魚不吃魚吖_),每周報(bào)最新復(fù)刻信息(數(shù)據(jù)來源于豆瓣小組(放我出趕due)的返場(chǎng)先祖記錄貼)\n
2.聊天關(guān)鍵詞(消息攜帶)
(每日任務(wù)|今日任務(wù)) 會(huì)觸發(fā)小助手私聊每日任務(wù)
(近期先祖|最新復(fù)刻) 會(huì)觸發(fā)小助手私聊最新復(fù)刻信息
(先祖在哪里|先祖位置) 會(huì)觸發(fā)小助手私聊詢問你想知道哪里先祖的位置,回答小助手會(huì)發(fā)送對(duì)應(yīng)攻略
(小金人在哪里|小金人位置) 會(huì)觸發(fā)小助手私聊詢問你想知道哪里小金人的位置,回答小助手會(huì)發(fā)送對(duì)應(yīng)攻略
(近期活動(dòng)) 會(huì)觸發(fā)小助手私聊發(fā)送官方微博地址
(群沒有開啟私聊的話請(qǐng)自行添加小助手)\n
3.特殊功能
@我 (1|開啟夸人模式|夸我) 開啟彩虹屁模式
@我 (0|再見|安靜) 關(guān)閉彩虹屁模式
`)
}
}
// 處理對(duì)話
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("今日任務(wù)") != -1 || text.indexOf("今天任務(wù)") != -1 || text.indexOf("每日任務(wù)") != -1) {
client.sendPrivateMsg(data.user_id, imgList + '\n以上就是今日份的小小幸運(yùn)喲~')
} else if (text.indexOf("近期先祖") != -1 || text.indexOf("最新先祖") != -1 || text.indexOf("最新復(fù)刻") != -1) {
client.sendPrivateMsg(data.user_id, `近期復(fù)刻先祖消息!${fukeTime}\n [CQ:image,cache=0,file=${fukeImg}] \n數(shù)據(jù)來源于豆瓣小組(放我出趕due)的返場(chǎng)先祖記錄貼`)
} else if (text.indexOf("近期活動(dòng)") != -1) {
client.sendPrivateMsg(data.user_id, `${sex}請(qǐng)?jiān)诠俜轿⒉┎榭?https://m.weibo.cn/u/6355968578#_loginLayer_1602073018866`)
} else if ((text.indexOf("先祖在哪里") != -1 || text.indexOf("先祖位置") != -1) && text.indexOf("復(fù)刻先祖") == -1) {
client.sendPrivateMsg(data.user_id, `${sex}請(qǐng)告訴我你想知道的先祖位置!\n 例如 晨島`)
} else if (text.indexOf("小金人在哪里") != -1 || text.indexOf("小金人位置") != -1) {
client.sendPrivateMsg(data.user_id, `${sex}請(qǐng)告訴我你想知道的小金人位置! \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]`)
}
}
}
}
// 獲取復(fù)刻先祖圖片
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("http://div[@class='image-wrapper']/img/@src", doc)
let text = xpath.select("http://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()
})
})
})
}
// 獲取每日任務(wù)
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("http://figure/figcaption/text()", doc).forEach(item => {
titleList.push(item.data)
})
let i = -1
imgList = xpath.select("http://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?'這個(gè)圖片我就不解釋咯!':titleList[i]}`
}
}).join(" ")
resFn()
})
})
})
})
})
}
// 定時(shí)函數(shù)
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)
}
});
});
//每周三發(fā)送:
schedule.scheduleJob('59 59 6 * * 3', async () => {
await getAncestor()
Object.keys(qunList).forEach(async (item) => {
await sendMsg(item)
});
});
}
// 發(fā)送定時(shí)消息
function sendMsg(item, type) {
return new Promise(resFn => {
if (type) {
client.sendGroupMsg(item, imgList + '\n' + zaoCi[getRandomInt(100)])
} else {
client.sendGroupMsg(item, `近期復(fù)刻先祖消息!${fukeTime}\n [CQ:image,cache=0,file=${fukeImg}] \n數(shù)據(jù)來源于豆瓣小組(放我出趕due)的返場(chǎng)先祖記錄貼`)
}
resFn()
})
}
// 隨機(jī)取一句話
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;
測(cè)試機(jī)器人群號(hào) 334014763