NTQQ + LLOneBot(5.0以上)+ NoneBot2 实现你的QQ机器人

工具介绍

  1. NTQQ 是腾讯的新一代QQ桌面版(NT架构),不是工具,而是QQ软件本身。
  2. LLOneBot(5.0以上) 是一个为 NTQQ 设计的机器人协议工具,用于连接 QQ 和你的机器人程序(如 NoneBot2)。它支持 OneBot V11 和 Satori 协议,负责接收 QQ 消息(如群聊消息)并转发给你的代码,或者将代码的回复发送回 QQ。
  3. NoneBot2 是一个Python开发的通用机器人框架,社区插件丰富,适合快速开发简单功能。它专注逻辑开发,接收LLOneBot传来的消息,运行你的代码。不负责QQ连接(需搭配NapCat或LLOneBot)。

快速开始

  1. 腾讯QQ官网下载最新NTQQ客户端,安装并登录你的QQ账号。

  2. 安装 LLOneBot(参考官方文档

    • 下载 LLOneBot-win-x64-ffmpeg.zip
    • 解压后双击 llonebot.exe 会启动 QQ,登录后会在 llonebot.exe 所在目录生成一个 data 文件夹(注意在登录的时候不能勾选多个账号,LLOneBot 不支持这种登录方式)
  3. 安装NoneBot2,打开命令行运行:pip install nonebot2

  4. 创建 NoneBot2 项目:

    • 运行命令:nb create
    • 选择simple(插件开发者)
    • 输入项目名称
    • 选择 One Bot V11 协议
    • 选择FastAPI 驱动器
    • 插件存储位置随意
    • 立即安装依赖
    • 是否创建虚拟环境看你自己(笔者的nonebot本来就是在虚拟环境里的,所以就选择了no)
    • 内置插件选择echo (便于测试机器人是否正常)
  5. 启动机器人

    1
    2
    3
    # 运行以下命令来启动你的机器人:
    cd (你之前输入的项目名)
    nb run --reload
    你会看到一条日志:[INFO] uvicorn | Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit),记住这个8080端口

  6. 配置 LLOneBot:

    • 浏览器打开 http://localhost:3080 进行配置
    • 添加反向 WS 地址为:ws://127.0.0.1:8080/onebot/v11/ws, 这里的 8080 是 NoneBot 输出的端口号,/onebot/v11/ws 是 NoneBot onebot 适配器默认的路径
    • 点击保存配置
    • 这时在nonebot的日志中就能看到你的bot connected了,并且会显示接收到的消息
  7. 向你的bot发送 /echo hello 进行测试(群聊中需要先@bot)

编写Bot代码(以CF比赛推送为例)

  1. 创建插件:nb plugin create

    • 输入插件名称,这里以 Codeforces 为例
    • 选择no,这里不使用嵌套插件
    • 插件存储位置,默认第一个
  2. plugins\codeforces 目录下新建一个文件 fetcher.py,内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    import requests
    from datetime import datetime

    # 简化比赛名称的函数
    def simplify_name(name):
    if 'Codeforces ' in name:
    name = name.replace('Codeforces ', '')
    if 'Round ' in name:
    name = name.replace('Round ', '')
    if 'Educational' in name:
    name = name.replace('Educational', 'Edu')
    return name

    # 转换Unix时间戳为指定日期格式
    def format_time(start_time):
    dt = datetime.fromtimestamp(start_time)
    return dt.strftime('%Y-%m-%d %H:%M')


    def fetch_contest_info():
    url = 'https://codeforces.com/api/contest.list'
    response = requests.get(url, timeout=10)
    data = response.json()

    if data['status'] != 'OK':
    return "无法获取比赛信息"

    contests = data['result']

    # 筛选phase为"BEFORE"的比赛,并按startTimeSeconds升序排序(最近的先)
    upcoming_contests = [c for c in contests if c['phase'] == 'BEFORE']
    upcoming_contests.sort(key=lambda x: x['startTimeSeconds'])

    # 使用列表收集输出内容
    output_lines = []

    num_contests = len(upcoming_contests)
    output_lines.append(f'已找到 {num_contests} 条最近的比赛:')

    for contest in upcoming_contests:
    simple_name = simplify_name(contest['name'])
    date_time = format_time(contest['startTimeSeconds'])
    output_lines.append(f'◉ {simple_name}')
    output_lines.append(f' {date_time}\n')

    # 将列表中的所有行连接成一个字符串
    return '\n'.join(output_lines)

  3. 修改 __init__.py 文件内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    from nonebot import get_plugin_config
    from nonebot.plugin import PluginMetadata

    from .config import Config

    __plugin_meta__ = PluginMetadata(
    name="Codeforces",
    description="",
    usage="",
    config=Config,
    )

    config = get_plugin_config(Config)


    from nonebot import on_command
    from .fetcher import fetch_contest_info

    CF = on_command("cf")


    @CF.handle()
    async def handle_function():
    await CF.finish(fetch_contest_info())

  4. 此时你向bot发送 /cf 就可以获取到比赛信息了

其他功能参考NoneBot2官方指南