← 返回博客列表

智能基座智享未来ep02:用 AstrBot + NapCat 打造每日科技资讯 QQ 机器人

ryou

原文地址:https://www.cnblogs.com/ryuo-ou/p/19686674 同步说明:该文已完整同步到站内博客,便于统一检索和阅读。

引言

你是否想要一个能在群里每天自动推送前沿科技文章的 QQ 机器人?既不需要高昂的服务器费用,又能完全掌控功能?本文将手把手教你如何利用开源框架 AstrBotNapCat 搭建一个稳定、可扩展的 QQ 机器人,并编写插件实现定时推送科技新闻。即使你是编程新手,也能跟着步骤一步步完成。

为什么使用第三方框架?

官方 QQ 机器人限制较多(每月仅 4 条主动消息、无法定时推送、需实名认证),而第三方框架如 NapCat + AstrBot 能实现:

  • ✅ 完全自由的定时推送
  • ✅ 支持发送图文、链接
  • ✅ 可编写插件扩展功能
  • ✅ 无消息数量限制

当然,代价是账号存在被腾讯风控的风险,因此务必使用专用小号进行测试。


一、环境准备

1. 安装 Docker

AstrBot 和 NapCat 都通过 Docker 容器运行,因此你需要先安装 Docker Desktop(Windows/Mac)或 Docker Engine(Linux)。

  • 访问 Docker官网 下载对应版本并安装。
  • 安装完成后,打开终端(Windows 用户使用 PowerShell)运行 docker --version 确认安装成功。

2. 一键部署脚本

AstrBot 官方提供了一键部署脚本,能自动拉取镜像并启动容器。在终端中执行以下命令(以 Windows PowerShell 为例):

irm https://gitee.com/jun-wan/script/raw/master/astrbot/deploy_astrbot.ps1 | iex

脚本运行过程中会询问是否使用镜像加速器,国内用户推荐选择 1. 毫秒镜像 以加快下载速度。如果遇到镜像拉取失败,可参考后文的“常见问题”部分。

脚本执行成功后,会在当前用户的目录下创建 astrbot 文件夹,内含 astrbot.yml 配置文件,并启动两个容器:astrbot-astrbot-1astrbot-napcat-1


二、配置 NapCat(登录机器人 QQ)

NapCat 是负责与 QQ 服务器通信的组件,我们需要通过它的 Web 界面登录机器人 QQ 号。

  1. 访问 NapCat 管理后台:打开浏览器,访问 http://localhost:6099
  2. 获取登录 Token:回到终端,查看 NapCat 容器的日志:
    docker logs astrbot-napcat-1
    
    找到类似 Token: xxxxxxxx 的一行,复制该 Token。
  3. 登录后台:在浏览器页面输入 Token,进入 NapCat 管理界面。
  4. 扫码登录 QQ:点击“登录 QQ”,用你的机器人小号扫描二维码完成登录。

登录成功后,NapCat 会自动生成配置文件,并监听反向 WebSocket 端口(默认为 6195 或 6199,取决于配置)。


三、配置 AstrBot(机器人大脑)

AstrBot 是机器人逻辑的核心,提供 Web 管理界面和插件系统。

  1. 访问 AstrBot 后台:浏览器打开 http://localhost:6185

  2. 首次登录:默认用户名和密码均为 astrbot,登录后请立即修改密码(日志中会有安全提醒)。

  3. 创建机器人适配器

    • 左侧菜单点击【机器人】→【创建机器人】。
    • 消息平台类别选择 OneBotv11(因为 NapCat 使用该协议)。
    • 机器人名称可任意填写,如“科技推送助手”。
    • 反向 WebSocket 主机:0.0.0.0,端口:6195(注意:实际端口需与 NapCat 配置一致,请查看下一步)。
    • 点击保存。
  4. 确认 NapCat 连接地址

    • 回到 NapCat 管理后台(http://localhost:6099),找到“OneBot 配置”或“网络配置”。
    • 查看反向 WebSocket 地址,应设置为 http://astrbot:6195/ws(如果 AstrBot 端口是 6195)。
    • 如果不一致,修改 NapCat 中的地址,保存后 NapCat 会自动重连。
  5. 验证连接:在 AstrBot 后台点击【平台日志】,如果看到类似 aiocqhttp(OneBot v11) 适配器已连接 的提示,说明两者成功握手。


四、开发插件:每日科技文章推送

AstrBot 的插件机制让我们可以轻松扩展功能。我们将编写一个插件,实现两个功能:

  • 手动指令:用户在群里 @机器人 并发送 /tech_news,立即获取最新科技文章。
  • 定时推送:每天早上 9 点,机器人自动向指定群发送文章摘要。

1. 创建插件目录

C:\Users\你的用户名\astrbot\astrbot\data\plugins\ 下新建文件夹,命名为 astrbot_plugin_daily_tech(必须以 astrbot_plugin_ 开头)。

在该文件夹内创建两个文件:

  • metadata.yaml:插件的元信息。
  • main.py:插件主代码。

2. 编写 metadata.yaml

plugin_name: "astrbot_plugin_daily_tech"
author: "你的昵称"
version: "1.0.0"
description: "每天定时在群里发送前沿科技文章"

3. 编写 main.py

import asyncio
import aiohttp
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from datetime import datetime
from astrbot.api.event import filter, AstrMessageEvent
from astrbot.api.star import Context, Star, register
from astrbot.api import logger
from astrbot.api.message_components import Plain async def fetch_tech_news(): """从 RSS 源获取最新科技文章标题和链接""" rss_url = "https://www.ithome.com/rss/" articles = [] # 添加 Headers 模拟浏览器 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } # 定义 AI 相关的关键词 ai_keywords = ["AI", "人工智能", "GPT", "大模型", "DeepSeek", "OpenAI", "Gemini", "Claude", "LLM", "Sora", "机器学习", "神经网络", "算力", "英伟达", "NVIDIA", "机器人", "Copilot"] try: async with aiohttp.ClientSession() as session: async with session.get(rss_url, headers=headers, timeout=15) as resp: if resp.status == 200: # 使用 read() 获取字节数据,避免编码问题 xml_data = await resp.read() import xml.etree.ElementTree as ET try: root = ET.fromstring(xml_data) # RSS 2.0 的路径通常是 channel/item # 获取更多文章进行筛选(前 30 条),以确保能过滤出 AI 内容 for item in root.findall('.//item')[:30]: title = item.find('title').text link = item.find('link').text # 关键词匹配,不区分大小写 if any(k.lower() in title.lower() for k in ai_keywords): articles.append({"title": title, "link": link}) if len(articles) >= 8: # 限制最大条数,避免消息过长 break except ET.ParseError as e: logger.error(f"RSS XML 解析失败: {e}. 返回内容前100字: {xml_data[:100]}") return "解析 RSS 数据失败,可能是源站结构发生了变化。" else: logger.error(f"获取 RSS 失败,状态码: {resp.status}") except Exception as e: logger.error(f"获取文章时出错: {e}") if not articles: return "🤖 今天暂时没有检测到 AI 相关的热门新闻,晚点再来看看吧~" # 美化输出格式 today_str = datetime.now().strftime("%Y-%m-%d") news_content = f"🤖 每日 AI 前沿播报\n📅 {today_str}\n" news_content += "═══════════════\n" for i, article in enumerate(articles, 1): news_content += f"{i}. {article['title']}\n" news_content += f" 🔗 {article['link']}\n\n" news_content += f"来源:IT之家 | 共精选 {len(articles)} 条资讯" return news_content @register("daily_tech_news", "智能基座", "每天定时推送科技文章", "1.0.0")
class DailyTechNewsPlugin(Star): def __init__(self, context: Context): super().__init__(context) # 这里可以初始化一些配置,比如目标群号、推送时间 self.target_group_id = "1003749165" # 替换成你的群号 self.push_time = "09:00" # 设定推送时间 # 初始化 scheduler self.scheduler = AsyncIOScheduler() self.scheduler.add_job(self.daily_push, 'cron', hour=9, minute=0) self.scheduler.start() async def _push_news_to_group(self): """内部方法:获取新闻并推送到群""" news_message = await fetch_tech_news() # 主动发送消息到群 await self.context.send_message( "aiocqhttp", # 平台适配器名称,OneBot v11 用这个 [Plain(news_message)], # 消息内容,用 Plain 包装纯文本 self.target_group_id, # 目标群号 is_group=True # 表明这是一个群消息 ) logger.info(f"已向群 {self.target_group_id} 推送科技新闻。") async def daily_push(self): """定时任务入口""" logger.info("定时任务触发:准备推送科技新闻。") # 注意:定时任务本身是由系统触发的,event 可能没有发送者信息。 # 我们直接调用内部方法发送。 await self._push_news_to_group() # 由于是定时任务,不需要通过 yield 返回结果给某个用户 @filter.command("tech_news") async def manual_tech_news(self, event: AstrMessageEvent): """指令:手动查看科技新闻""" news = await fetch_tech_news() yield event.plain_result(news)

4. 安装插件

  • 将上述文件保存后,在 AstrBot WebUI 左侧点击【插件】,你应该能看到 daily_tech_news 插件。如果未显示,请重启 AstrBot 容器:
    cd C:\Users\你的用户名\astrbot\astrbot
    docker compose -f astrbot.yml restart
    
  • 插件显示后,确保其状态为“已启用”。

5. 开启主动型能力

为了让定时任务生效,需要在 AstrBot 后台【配置】中开启 “主动型能力”(Proactive Agent),然后保存。


五、测试与调试

测试手动指令

在机器人所在的群里,@机器人并发送 /tech_news。正常情况下,机器人应该回复最新的科技文章列表。

如果没有任何反应,请按以下步骤排查:

  1. 查看 AstrBot 平台日志:是否有你的指令被接收的记录?
  2. 检查插件日志:在代码中添加 logger.info 输出,确认函数是否执行。
  3. 测试网络连通性:进入 AstrBot 容器,尝试 curl https://www.jiqizhixin.com/rss,确认能访问外网。
  4. 简化 fetch 函数:暂时返回固定字符串,排除网络问题。

测试定时推送

可以临时修改定时任务的 cron 表达式为下一分钟(例如当前时间 14:30,则设为 14:31),观察是否推送。成功后改回 9:00


六、常见问题与解决方案

1. Docker 镜像拉取失败

现象:执行一键部署脚本时,镜像下载缓慢或报错 not found

解决

  • 更换更稳定的镜像加速器,如 DaoCloud(m.daocloud.io/docker.io)。
  • 手动拉取镜像后再运行脚本:
    docker pull m.daocloud.io/docker.io/soulter/astrbot:latest
    docker pull m.daocloud.io/docker.io/mlikiowa/napcat-docker:latest
    
  • 为本地镜像打标签:
    docker tag m.daocloud.io/docker.io/mlikiowa/napcat-docker:latest mlikiowa/napcat-docker:latest
    docker tag m.daocloud.io/docker.io/soulter/astrbot:latest soulter/astrbot:latest
    

2. NapCat 连接 AstrBot 时报 405 错误

现象:NapCat 日志显示 Unexpected server response: 405

原因:WebSocket 连接地址的端口或路径不正确。

解决

  • 确认 AstrBot 实际监听的端口(可在 data/cmd_config.json 中查找 ws_port)。
  • 在 NapCat 后台将反向 WebSocket 地址修改为 ws://astrbot:正确端口(例如 6195)。
  • 如果仍有问题,尝试在地址后加路径 /ws/onebot/v11/ws

3. 定时任务装饰器 @filter.cron 不存在

现象:导入时提示 module 'astrbot.api.event.filter' has no attribute 'cron'

原因:AstrBot 版本差异,该装饰器可能位于 timer 模块或已被移除。

解决

  • 尝试使用 from astrbot.api import timer@timer.cron(...)
  • 或者直接在 __init__ 中通过 self.context.scheduler.add_job 手动添加任务(本文采用此方法)。

4. 插件已加载但指令无响应

现象:日志显示收到消息,但无回复。

可能原因

  • 插件未正确重载(修改代码后需点击“重载”按钮)。
  • 指令名称冲突(尝试改为不常见的名字,如 /mytech)。
  • yield event.plain_result 在某些版本中无效,改用 self.context.send_message 直接发送。

七、进阶与扩展

1. 添加多个 RSS 源

fetch_tech_news 中并发抓取多个 RSS 源,合并后去重推送。

2. 格式化消息

可使用更丰富的消息组件,如图片(NapCat 支持发送网络图片)、Markdown(需 QQ 客户端支持)等。

3. 接入 AI 聊天功能

在 AstrBot 后台【服务提供商】中配置一个模型(如硅基流动的免费模型),机器人就能智能回复普通消息。


八、总结与建议

通过本文,你从零开始搭建了一个功能完整的 QQ 科技资讯机器人。整个过程涉及 Docker 部署、组件配置、插件开发等多个环节,相信你对 AstrBot 的插件体系有了深入理解。

最后几点提醒:

  • 务必使用小号,避免主号被封。
  • 定期更新组件:NapCat 和 AstrBot 都在积极迭代,关注官方更新以获取新功能和修复。
  • 遵守法律法规:抓取内容时注意版权,勿用于非法用途。