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}") #直接删掉即可
这种方法最大的问题在于部署在自己电脑的上的bot需要至少保证过了0点电脑还开着,不然只能第二天手动删除数据库来保证正确性(半夜肯定是发言高峰期怎么关)。部署在云服务器的不需要考虑这个问题

第二个问题是N2好像不支持记录自己的消息(应该是我没找到)在go-cqhttp配置文件里有report-self-message,设置为TRUE就好了,但大部分的消息响应都是发起者一条bot一条,所以不会出现龙王变成bot的情况.....吧

第三个问题是这么处理消息会记录每一条对bot的指令也计入发言排行,虽然tx的龙王算法也是基于群聊发言次数,如果自己只想记录正常发言,N2的 rule类 里提供了一个 ToMeRule() 检查事件是否与机器人有关,这样在统计的时候可以对相关的事件进行过滤(没试过不清楚是不是这么个意思)

最后就是消息处理会对特定群聊每一个发言都进行日志输出,所以不管怎样日志都会很乱,不知道怎么解决只能自己克服了

posted @ 2022-05-18 16:44  FPICZEIT  阅读(519)  评论(0编辑  收藏  举报