Nonebot2插件:群聊发言排行
前言:请确保你已经阅读了并掌握了这篇文章 开头所提到的所有教程,并且配置好了属于你自己的bot
其他的和那篇文章里的一样,纯小白,中英文标点杂合着用,容易血压up
0.干什么的
众所周知QQ会给每天的水群最多的人给予一个龙王的标识,但不能做到具体每个人发言了多少次(好像手机QQ支持查看发言频率,但考虑到PCQQ和TIM用户,以及这个功能位置实属隐蔽,不如自己做一个)
官方商店和Github上都有更方便的插件,这里使用了轻量的sqlite3数据库进行操作,由于涉及到了SQL语句的使用,还请阅读接下来的内容前确保自己已经掌握了基础内容
菜鸟教程的sql教学 w3cschool的sql入门教程
1.具体操作
整体需要做的就是写两个处理函数,一个用于接收消息并放入数据库中进行增加,一个是用于查询当前群聊的发言排行
接收消息使用的是 on_message() ,记得在事件处理里写个rule不然对所有群聊都触发
接收消息代码如下
import nonebot
from nonebot.rule import *
from nonebot import on_command
from nonebot import *
from nonebot.plugin import on_keyword
from nonebot.adapters.onebot.v11 import Bot, Event, GroupMessageEvent
from nonebot.adapters.onebot.v11.message import Message
import sqlite3 #要不然打不开
async def shuiqun_rule(event:Event) ->bool :
with open("你的白名单存放地址.txt", encoding='utf-8') as file: #不用txt也是可以的
white_block = []
for line in file:
line = line.strip()
line = re.split("[ |#]", line)
white_block.append(line[0])
try:
whatever, group_id, user_id = event.get_session_id().split('_') # 获取当前群聊id,发起人id,返回的格式为group_groupid_userid
except: # 如果上面报错了,意味着发起的是私聊,返回格式为userid
group_id = None
user_id = event.get_session_id()
if group_id == None or group_id in white_block:
return True
else:
return False
shuiqun = on_message(rule=shuiqun_rule,priority=50)
@shuirun.handle() # 针对特定事项进行回复
async def shuirun_handle(bot: Bot, event: GroupMessageEvent):
await updade_fayan(user_id, group_id, data)
这里我们定义了一个 update_fayan() 的函数,用于在数据库中针对对于的群聊和用户进行次数增加
点我看
import sqlite3
async def updade_fayan(user_id, group_id, data):
rk = sqlite3.connect('你的数据库文件想存放的位置和名字.db') #不需要自己手动建一个,当没有链接到时sqlite3会自动新建一个db文件
# 判断是否存在群成员发言排行表
c = rk.cursor() # 新建一个数据库的游标
biaoming = "group" + group_id #对于每一个群聊都分别建一个表进行消息处理,表名随意,需要注意的是不能数字开头
c.execute(f'''CREATE TABLE if not exists {biaoming}
(ID int primary key not null,
cishu int not null
)
''')
'''
这里使用的是create table if not exists来判断是否存在一个以当前群聊命名的表
当然,这个的前提是当天群聊内有人发言。所以在设置消息接收的优先级时可以往高级设
或者可以每天0点新建一遍所有群聊的表名
表内列名只用写id——对应的发言人,cishu——该用户发言次数即可
如果想一表多用什么的就自己加吧
'''
# 判断当前群聊是否全部成员已加入(这部分并不需要写,可以只判断当前发言用户有没有加入,我这么写会导致后面一个地方出问题)
for i in data: #这个data是接受消息代码中获取的当前群聊用户列表
c.execute(f"select ID from {biaoming} where ID={i['user_id']}")
result = c.fetchone()
if result:
www = 1
else: #如果没有这个成员
c.execute(f"insert into {biaoming}(ID,cishu) VALUES ({i['user_id']}, 0)") #插入以taQQ号作为id的列,cishu设置为0
# 开始加发言次数
w = c.execute(f"select cishu from {biaoming} where ID={user_id}") #获取发言用户的发言次数
for row in w:
c.execute(f"update {biaoming} set cishu = {row[0] + 1} where ID ={user_id}") #更新,次数加一
rk.commit() #上传修改
rk.close() #一定要记得关闭
那么怎么记录发言次数的部分已经做完了,接下来编写获取排行的插件就十分简单了
点我看冗杂代码
import ast
import nonebot
import pandas as pd
from sqlalchemy import create_engine
from nonebot.rule import *
from nonebot import *
from nonebot.plugin import on_keyword
from nonebot.adapters.onebot.v11 import Bot, Event, GroupMessageEvent
from nonebot.adapters.onebot.v11.message import Message
import sqlite3
async def shuiqun_rule(event:Event) ->bool :
with open("你的白名单存放地址.txt", encoding='utf-8') as file: #不用txt也是可以的
white_block = []
for line in file:
line = line.strip()
line = re.split("[ |#]", line)
white_block.append(line[0])
try:
whatever, group_id, user_id = event.get_session_id().split('_') # 获取当前群聊id,发起人id,返回的格式为group_groupid_userid
except: # 如果上面报错了,意味着发起的是私聊,返回格式为userid
group_id = None
user_id = event.get_session_id()
if group_id in white_block:
return True
else:
return False
rank = on_command('rank', rule = shuiqun_rule,priority=50)
rk = sqlite3.connect('你数据库存放的地址.db')
@rank.handle()
async def rank_handle(bot: Bot, event: Event):
whatever, group_id, user_id = event.get_session_id().split('_')
data = await bot.call_api('get_group_member_list', **{
'group_id': int(group_id)
})
kr = rk.cursor()
gid = "group" + group_id #你表名咋写的就咋写
rank_value = kr.execute(f"SELECT * from {gid} ORDER BY cishu DESC") #获取以发言次数降序排序获得的列表
sss = f"当前群聊({group_id})发言排行为\n"
for i in rank_value:
for j in data:
if j['user_id'] == i[0] and i[1] != 0:#参考前面的函数,如果发言次数为0就不放上来
sss = sss + (j['card'] if j['card'] != "" else j['nickname']) + f"({i[0]}): " + str(i[1]) + "\n"
'''
这里大概是输出格式,按自己的喜好即可
有的时候群成员并未设置自己的群昵称,这时候就用QQ昵称就好了
'''
await rank.finish(Message(f"{sss}"))
最终实现效果
2.一些其他处理方式和待解决问题
首先是怎么保证每天更新(即每天都重新记录),这里用到了N2的定时任务插件
官方文档说明 , 官方商店插件
设置一下每天0点直接清空数据库里的文件即可
代码
定时插件还可以用来写很多其他内容,之后写的插件也会用到,如果不想自己装可以手动写个函数获取准确时间from nonebot import on_command, require, get_driver
from nonebot.typing import T_State
from nonebot.adapters import Bot, Event
from nonebot.adapters.onebot.v11.message import Message
import nonebot.adapters
import _thread
import os
import re
import sqlite3
scheduler = require('nonebot_plugin_apscheduler').scheduler
@scheduler.scheduled_job('cron', hour=0,minute=0) #定时清空发言排行
async def delete_fayan():
rk = sqlite3.connect('你数据库位置')
# 判断是否存在群成员发言排行表
c = rk.cursor()
with open("白名单地址", encoding='utf-8') as file:
white_block = []
for line in file:
line = line.strip()
line = re.split("[ |#]", line)
white_block.append(line[0])
for i in white_block:
group_id = "group" + str(i) #你自己定义的表名
c.execute(f"drop table if exists {group_id}") #直接删掉即可
第二个问题是N2好像不支持记录自己的消息(应该是我没找到)在go-cqhttp配置文件里有report-self-message,设置为TRUE就好了,但大部分的消息响应都是发起者一条bot一条,所以不会出现龙王变成bot的情况.....吧
第三个问题是这么处理消息会记录每一条对bot的指令也计入发言排行,虽然tx的龙王算法也是基于群聊发言次数,如果自己只想记录正常发言,N2的 rule类 里提供了一个 ToMeRule() 检查事件是否与机器人有关,这样在统计的时候可以对相关的事件进行过滤(没试过不清楚是不是这么个意思)
最后就是消息处理会对特定群聊每一个发言都进行日志输出,所以不管怎样日志都会很乱,不知道怎么解决只能自己克服了