Back to skills
extension
Category: OtherNo API key required

RSS个性化追踪摘要

每天自动抓取多源RSS,根据关键词权重筛选并生成带点击追踪跳转的个性化摘要,用户点击自动加权优化推送。

personAuthor: pasaidonhubclawhub

RSS 个性化追踪摘要系统

功能概述

每天自动抓取多个 RSS 源,根据用户设定的关键词权重筛选内容,生成带有点击追踪中转链接的个性化摘要。用户点击链接后自动记录并加权相关关键词,下次摘要优先推送相关类容。

核心流程:

RSS抓取 → 关键词打分 → 生成中转URL → 用户点击阅读 → 自动加权 → 下次优先推送

系统架构

┌─────────────────────────────────────────────────────────┐
│                    公网用户点击                          │
└───────────→ serveo.net 隧道 ────────────────────────────→┘
                                                 │
                                                 ▼
┌─────────────────────────────────────────────────────────┐
│         localhost:7890  (Node.js 中转服务器)            │
│  1. 记录点击到 /tmp/rss-clicks.log                    │
│  2. 返回 302 跳转到原文                                │
└─────────────────────────────────────────────────────────┘
                     ▲
                     │ SSH 隧道 (serveo.net)
                     │ Port 7890 → 公网
                     │
┌─────────────────────────────────────────────────────────┐
│         RSS 摘要生成脚本 (rss_summary.py)               │
│  1. 读取 rss-weights.json 配置                         │
│  2. 生成带中转URL的摘要                                │
│  3. 查询点击日志,加权被点关键词                       │
└─────────────────────────────────────────────────────────┘

核心文件

| 文件 | 用途 | |------|------| | rss-weights.json | 关键词权重配置(初始权重+历史加权记录) | | rss-redirect-server.js | Node.js 中转服务器(点击记录+302跳转) | | start.sh | 一键启动脚本(服务器+隧道) | | /tmp/rss-clicks.log | 点击日志(时间戳 + 来源IP + 目标URL) |


快速启动

1. 启动中转服务器

# 启动 Node.js 中转服务器
node /tmp/rss-redirect-server.js &

# 等待2秒,确认端口监听
sleep 2 && ss -tlnp | grep 7890

2. 建立 SSH 隧道(serveo.net)

# 后台运行 serveo.net 隧道
ssh -o StrictHostKeyChecking=no \
    -o ServerAliveInterval=30 \
    -R 80:localhost:7890 \
    serveo.net > /tmp/serveo.log 2>&1 &

# 等待6秒,提取公网URL
sleep 6 && cat /tmp/serveo.log | grep "Forwarding HTTP" | awk '{print $NF}'

输出示例:

https://ec850a76c13b9d96-123-234-101-41.serveousercontent.com

3. 更新配置

# 更新 rss-weights.json 中的 redirect_base
python3 -c "
import json
with open('/root/.openclaw/workspace/rss-weights.json') as f:
    w = json.load(f)
w['redirect_base'] = 'https://ec850a76c13b9d96-123-234-101-41.serveousercontent.com'
with open('/root/.openclaw/workspace/rss-weights.json', 'w') as f:
    json.dump(w, f, ensure_ascii=False, indent=2)
"

中转 URL 格式

格式:

{redirect_base}/go/{base64url_safe编码的原文URL}

生成示例(Python):

import base64

original = "https://www.highsnobiety.com/p/adidas-tokyo-mj-snakeskin/"
encoded = base64.b64encode(original.encode()).decode()
encoded = encoded.replace('+', '-').replace('/', '_').rstrip('=')
redirect_url = f"{redirect_base}/go/{encoded}"
# https://xxx.serveousercontent.com/go/aHR0cHM6Ly93d3cuaGlnaHNub2JpZXR5LmNvbS9wL2FkaWRhcy10b2t5by1tai1zbmFrZXNraW4v

点击日志格式

日志文件: /tmp/rss-clicks.log

格式:

[YYYY-MM-DD HH:MM:SS] FROM:<来源IP> -> <目标URL>

示例:

[2026-04-18 13:46:00] FROM:127.0.0.1 -> https://www.highsnobiety.com/p/adidas-tokyo-mj-snakeskin/

关键词匹配规则:

  • 精确匹配标题/摘要中的关键词
  • 大小写不敏感
  • 每命中一次,关键词权重 +1

关键词权重配置

文件: /root/.openclaw/workspace/rss-weights.json

结构:

{
  "version": "1.1",
  "last_updated": "2026-04-18",
  "redirect_base": "https://xxx.serveousercontent.com",
  "server_url": "http://localhost:7890",
  "keywords": {
    "Nike": 4,
    "Adidas": 4,
    "耐克": 4,
    "阿迪达斯": 4,
    "运动鞋服": 3
  },
  "base_weights": {
    "Nike": 4,
    "Adidas": 4,
    "耐克": 4
  },
  "history": [
    {
      "date": "2026-04-18 13:46",
      "source": "click",
      "url": "https://www.highsnobiety.com/...",
      "incremented": ["Adidas: 3 -> 4", "球鞋: 2 -> 3"]
    }
  ]
}

手动加权命令:

python3 << 'PYEOF'
import json

with open('/root/.openclaw/workspace/rss-weights.json') as f:
    w = json.load(f)

target_kws = ['Nike', 'Adidas', '耐克', '阿迪达斯']
updated = []

for kw, wgt in w['keywords'].items():
    if kw in target_kws:
        w['keywords'][kw] = wgt + 1
        updated.append(f"{kw}: {wgt} -> {wgt+1}")

w['history'].append({
    'date': '2026-04-18 14:00',
    'source': 'manual',
    'incremented': updated
})

with open('/root/.openclaw/workspace/rss-weights.json', 'w') as f:
    json.dump(w, f, ensure_ascii=False, indent=2)

print("已更新:", updated)
PYEOF

服务管理

查看服务状态

# 中转服务器
ss -tlnp | grep 7890

# serveo 隧道
ps aux | grep serveo.net | grep -v grep

# 点击日志
cat /tmp/rss-clicks.log | tail -10

重启中转服务器

# 杀掉旧进程
kill $(ps aux | grep "rss-redirect-server" | grep -v grep | awk '{print $2}') 2>/dev/null

# 重启
node /tmp/rss-redirect-server.js &

重启隧道

# 杀掉旧隧道
kill $(ps aux | grep "serveo.net" | grep -v grep | awk '{print $2}') 2>/dev/null
sleep 1

# 启动新隧道
ssh -o StrictHostKeyChecking=no \
    -o ServerAliveInterval=30 \
    -R 80:localhost:7890 \
    serveo.net > /tmp/serveo.log 2>&1 &

健康检查

curl -s "http://localhost:7890/health"
# 输出: OK

RSS 摘要生成流程

触发时机

  • 手动触发:用户说"做一次摘要"或"发摘要"
  • 自动触发:每日定时(通过 cron 配置)

生成步骤

1. 读取 rss-weights.json 中的关键词权重
2. 抓取所有配置的 RSS 源
3. 对每条内容计算权重得分:
   score = Σ(命中关键词的权重)
4. 按 score 降序排列
5. 生成带中转 URL 的摘要
6. 输出格式:
   序号:中文内容概要
   [点击查看详情](中转URL)

输出格式

**📡 今日热讯 · YYYY-MM-DD(个性化加权版)**

**1. [标题]**
[中文摘要,不超过100字]
[点击查看详情](中转URL)

**2. [标题]**
...

RSS 源配置

默认 RSS 源:

| 源 | URL | 类型 | |----|-----|------| | IT之家 | https://www.ithome.com/rss/ | 科技 | | 钛媒体 | https://www.tmtpost.com/rss | 科技 | | 36kr | https://36kr.com/feed | 科技/商业 | | 爱范儿 | https://www.ifanr.com/feed | 科技 | | Highsnobiety | https://www.highsnobiety.com/feed/ | 潮流 | | Complex | https://www.complex.com/feed | 潮流/音乐 | | The Decoder | https://the-decoder.com/feed/ | AI/科技 | | Mashable | https://mashable.com/feed | 科技 |


故障排查

serveo 隧道断开

症状: 用户点击链接无响应

排查:

ps aux | grep serveo | grep -v grep
# 如果没有输出,隧道已断开

解决:

kill $(ps aux | grep "rss-redirect" | grep -v grep | awk '{print $2}') 2>/dev/null
sleep 1
node /tmp/rss-redirect-server.js &
sleep 1
ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=30 -R 80:localhost:7890 serveo.net > /tmp/serveo.log 2>&1 &
sleep 6
cat /tmp/serveo.log

中转服务器崩溃

症状: curl localhost:7890 无响应

解决:

node /tmp/rss-redirect-server.js &

点击未记录

排查:

cat /tmp/rss-clicks.log | tail -5

可能原因:

  1. 用户未完成 interstitial 确认页(serveo 免费版限制)
  2. 隧道超时断开
  3. 用户点击的是原文 URL 而不是中转 URL

base64 解码错误

症状: 日志中出现 (decode error)

排查:

# 测试编码
import base64
url = "https://example.com"
enc = base64.b64encode(url.encode()).decode()
print(f"Encoded: {enc}")
print(f"Decoded: {base64.b64decode(enc).decode()}")

局限性

  1. serveo.net 免费版:跳转前需点 interstitial 确认页,无法绕过
  2. SSH 隧道稳定性:长时间运行可能断开,需配置自动重连
  3. 点击归属:依赖 IP 和 User-Agent,不保证100%准确
  4. 服务器在国外:国内访问 Cloudflare 可能不稳定

使用方法

首次启动:

cd /root/.openclaw/workspace/skills/rss-personalized-digest
bash start.sh

生成摘要:

  1. 运行 feed fetch -o wide 获取最新内容
  2. 根据权重筛选生成带中转 URL 的摘要
  3. 发送前查询 /tmp/rss-clicks.log 对被点关键词 +1

查看点击日志:

curl -s http://localhost:7890/clicks
# 或
cat /tmp/rss-clicks.log

手动加权: 修改 rss-weights.jsonkeywords 字典对应关键词的值,+1 累加。


扩展方案

方案一:Cloudflare Workers(推荐)

  • 优点:无拦截跳转,永久固定域名,全球 CDN
  • 缺点:需用户手动部署 Worker 代码
  • 部署:见下方附录

方案二:自建 VPS

  • 在有公网 IP 的服务器上运行中转服务
  • 优点:完全可控,无第三方限制
  • 配置:Nginx 反向代理 + 固定域名

附录:Cloudflare Workers 部署代码

export default {
  async fetch(request) {
    const url = new URL(request.url);
    const path = url.pathname;

    if (path.startsWith('/go/')) {
      let b64 = path.slice(4).replace(/-/g, '+').replace(/_/g, '/');
      while (b64.length % 4) b64 += '=';
      let originalUrl;
      try {
        originalUrl = atob(b64);
      } catch (e) {
        return new Response('Invalid URL', { status: 400 });
      }

      // 发送点击日志到中转服务器
      fetch('http://YOUR_TUNNEL_URL/log?url=' + encodeURIComponent(originalUrl), {
        method: 'GET',
        mode: 'no-cors'
      }).catch(() => {});

      return Response.redirect(originalUrl, 302);
    }

    return new Response('RSS Click Logger\nUsage: /go/<base64url>', { status: 200 });
  }
};

部署步骤:

  1. 登录 https://dash.cloudflare.com
  2. Workers 和 Pages → 创建应用程序 → 创建 Worker
  3. 粘贴代码,Deploy
  4. 将返回的域名填入 rss-weights.jsonredirect_base