240 lines
7.7 KiB
Markdown
240 lines
7.7 KiB
Markdown
---
|
||
name: blogwatcher-daily
|
||
description: RSS 订阅监控 + 每日笔记生成。使用 RSSHub + feedparser 抓取 31 个订阅,自动去重并存入 SQLite,新文章追加写入 Markdown 笔记。
|
||
version: 1.0
|
||
category: custom
|
||
tags: [rss, blog, monitoring, automation]
|
||
metadata:
|
||
author: Hermes Agent
|
||
last_updated: 2025-04-19
|
||
platform: macos, ubuntu
|
||
custom_skill_path: /Users/weishen/.hermes/skills/custom/
|
||
installation_note: "blogwatcher-daily 脚本在 Mac mini 本地运行(依赖 feedparser)。需要 RSSHub 服务(http://192.168.3.45:1200)访问 YouTube/Bilibili 等被墙源。"
|
||
---
|
||
|
||
# Blogwatcher Daily
|
||
|
||
RSS 订阅监控 + 每日笔记生成自动化。
|
||
|
||
## 依赖
|
||
|
||
```bash
|
||
pip3 install feedparser
|
||
```
|
||
|
||
> feedparser 是 Python 最成熟的 RSS 解析库,支持 RSS 1.0/2.0/Atom、任意编码、畸形 XML。
|
||
|
||
## 实际抓取架构(重要)
|
||
|
||
```
|
||
YouTube 频道 URL
|
||
↓ 脚本自动识别并转为 RSSHub 格式
|
||
http://192.168.3.45:1200/youtube/channel/{id}
|
||
↓
|
||
curl → RSSHub → YouTube
|
||
|
||
普通 RSS(Engadget, Slashdot 等)
|
||
↓ 脚本直接访问(绕过 RSSHub /rss/ 路由)
|
||
原始 RSS URL
|
||
↓
|
||
curl → 目标网站
|
||
```
|
||
|
||
**关键发现**:RSSHub 的 `/rss/{url}` 路由不稳定(返回 RSSHub 欢迎页),
|
||
因此普通 RSS 源直接访问,不走 RSSHub 代理。
|
||
|
||
脚本内部 `build_fetch_url()` 根据 URL 类型自动选择路由:
|
||
- YouTube → RSSHub
|
||
- 已有的 RSSHub URL → 直接使用
|
||
- 其他 → 直接访问原始 URL
|
||
|
||
```
|
||
YouTube 频道 URL
|
||
↓ 脚本自动识别并转为 RSSHub 格式
|
||
http://192.168.3.45:1200/youtube/channel/{id}
|
||
↓
|
||
curl → RSSHub → YouTube
|
||
|
||
普通 RSS(Engadget, Slashdot 等)
|
||
↓ 脚本直接访问(绕过 RSSHub /rss/ 路由)
|
||
原始 RSS URL
|
||
↓
|
||
curl → 目标网站
|
||
```
|
||
|
||
**关键发现**:RSSHub 的 `/rss/{url}` 路由不稳定(返回 RSSHub 欢迎页),
|
||
因此普通 RSS 源直接访问,不走 RSSHub 代理。
|
||
|
||
脚本内部 `build_fetch_url()` 根据 URL 类型自动选择路由:
|
||
- YouTube → RSSHub
|
||
- 已有的 RSSHub URL → 直接使用
|
||
- 其他 → 直接访问原始 URL
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
~/.hermes/skills/custom/blogwatcher-daily/
|
||
├── SKILL.md # 本文件
|
||
├── scripts/
|
||
│ └── blogwatcher-daily.py # 主脚本
|
||
├── subscriptions.txt # 订阅列表(name|URL)
|
||
└── blogwatcher.db # SQLite 数据库(自动创建)
|
||
```
|
||
|
||
## 使用方法
|
||
|
||
### 扫描订阅(默认)
|
||
|
||
```bash
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py
|
||
```
|
||
|
||
- 扫描所有订阅,新增文章存入数据库
|
||
- 生成今日笔记:`~/Workspace/nexus/ishenwei/blogwatcher/YYYY-MM-DD.md`
|
||
|
||
### 添加订阅
|
||
|
||
```bash
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py \
|
||
--add "频道名" "URL"
|
||
```
|
||
|
||
**YouTube 频道自动转换**:直接贴 YouTube 频道 URL 或 feed URL,
|
||
脚本自动识别并转为 RSSHub 格式,无需手动拼接。
|
||
|
||
```bash
|
||
# 以下三种方式效果相同:
|
||
--add "Tech With Tim" "https://www.youtube.com/channel/UC4JX40jDee_tINbkjycV4Sg"
|
||
--add "Tech With Tim" "https://www.youtube.com/feeds/videos.xml?channel_id=UC4JX40jDee_tINbkjycV4Sg"
|
||
--add "Tech With Tim" "http://192.168.3.45:1200/youtube/channel/UC4JX40jDee_tINbkjycV4Sg"
|
||
```
|
||
|
||
### 列出订阅
|
||
|
||
```bash
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py --list
|
||
```
|
||
|
||
### 仅扫描(不写文件)
|
||
|
||
```bash
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py --scan-only
|
||
```
|
||
|
||
### 强制回扫(`--all`)
|
||
|
||
```bash
|
||
# 强制抓取每频道10篇(忽略已读状态),写入独立文件
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py --all
|
||
|
||
# 测试模式:只打印,不写文件
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py --scan-only --all
|
||
```
|
||
|
||
- 输出文件:`~/Workspace/nexus/ishenwei/blogwatcher/all-YYYY-MM-DD.md`(**覆盖模式**,每次运行覆盖)
|
||
- **不混入**每日报告 `YYYY-MM-DD.md`
|
||
- 每频道最多10篇
|
||
- 用途:历史内容回扫、测试订阅状态
|
||
|
||
### 标记已读
|
||
|
||
```bash
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py --mark-read
|
||
```
|
||
|
||
## 添加订阅示例
|
||
|
||
### YouTube 频道
|
||
|
||
```bash
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py \
|
||
--add "Tech With Tim" "http://192.168.3.45:1200/youtube/channel/UC4JX40jDee_tINbkjycV4Sg"
|
||
```
|
||
|
||
### Bilibili
|
||
|
||
```bash
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py \
|
||
--add "B站频道" "http://192.168.3.45:1200/bilibili/user/{uid}"
|
||
```
|
||
|
||
### 普通 RSS
|
||
|
||
```bash
|
||
python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py \
|
||
--add "博客名" "http://192.168.3.45:1200/rss/https://example.com/feed.xml"
|
||
```
|
||
|
||
## RSSHub vs 直接 RSS
|
||
|
||
脚本自动判断路由,不需要手动选择:
|
||
|
||
| 源类型 | 路由方式 | 示例 |
|
||
|--------|----------|------|
|
||
| YouTube 频道/用户/feed | RSSHub | 自动识别并代理 |
|
||
| RSSHub URL(已存储) | 直接使用 | `http://192.168.3.45:1200/youtube/channel/...` |
|
||
| 普通 RSS(Engadget, Slashdot 等) | 直接访问 | `https://www.engadget.com/rss.xml` |
|
||
|
||
> ⚠️ RSSHub 的 `/rss/{url}` 代理路由**不稳定**(实测试返回欢迎页),普通 RSS 不要走 RSSHub。
|
||
|
||
## 配置
|
||
|
||
| 配置项 | 默认值 |
|
||
|--------|--------|
|
||
| RSSHub 地址 | `http://192.168.3.45:1200`(可设置 `RSSHUB_URL` 环境变量覆盖) |
|
||
| 笔记输出目录 | `~/Workspace/nexus/ishenwei/blogwatcher/` |
|
||
| 数据库 | `~/.hermes/skills/custom/blogwatcher-daily/blogwatcher.db` |
|
||
| 订阅列表 | `~/.hermes/skills/custom/blogwatcher-daily/subscriptions.txt` |
|
||
|
||
## Cron Job 设置
|
||
|
||
推荐每天早上 6:00 自动执行:
|
||
|
||
```bash
|
||
cronjob --create \
|
||
--name "Blogwatcher Daily" \
|
||
--schedule "0 6 * * *" \
|
||
--repeat 999 \
|
||
--deliver "telegram:5038825565" \
|
||
--prompt "使用 blogwatcher-daily 技能执行每日 RSS 扫描。
|
||
|
||
执行步骤:
|
||
1. 加载 blogwatcher-daily 技能
|
||
2. 运行:python3 ~/.hermes/skills/custom/blogwatcher-daily/scripts/blogwatcher-daily.py
|
||
3. 检查输出,确认写入的笔记文件路径
|
||
4. 如果有新文章,简短汇总发给我"
|
||
```
|
||
|
||
## 数据流程
|
||
|
||
1. **加载订阅**:从 `subscriptions.txt` 读取所有 name|URL 对
|
||
2. **URL 路由**:`build_fetch_url()` 自动判断:
|
||
- YouTube → 转为 `http://192.168.3.45:1200/youtube/channel/{id}`
|
||
- RSSHub URL → 直接使用
|
||
- 其他 → 直接访问原始 URL(绕过不稳定的 `/rss/` 路由)
|
||
3. **抓取**:curl 获取 XML,SSL 跳过验证
|
||
4. **解析**:feedparser 提取 title、link、description、pub_date
|
||
5. **去重**:按 link 去重,已存在则跳过
|
||
6. **存储**:新文章存入 SQLite
|
||
7. **输出**:**追加写入** Markdown 笔记(同一文件多次扫描不会覆盖,仅追加新链接)
|
||
- 读取已有文件,用正则提取现有链接 → 去重
|
||
- 新文章追加 `## 📦 新增 N 篇` 分隔块
|
||
|
||
## 已知问题
|
||
|
||
| 问题 | 说明 | 状态 |
|
||
|------|------|------|
|
||
| How to of the Day | wikiHow 完全封了爬虫 | ❌ 不可用 |
|
||
| How-To Geek | 远程服务器关闭连接 | ❌ 不可用 |
|
||
|
||
> feedparser 已修复:電腦玩物 ✅、阿榮福利味 ✅、异次元软件世界 ✅、Slashdot ✅
|
||
|
||
## 注意事项
|
||
|
||
- 首次使用需 `pip3 install feedparser`
|
||
- YouTube 路由需要 RSSHub 容器内配置 `HTTP_PROXY`/`HTTPS_PROXY` 环境变量
|
||
- 每次最多取每源 10 篇(TED Talks 等除外,取 20 篇)
|
||
- 数据库自动创建,无需手动初始化
|
||
- OPML 文件可用 Python 解析后批量导入(参考 /wiki-ingest 流程中的 OPML 解析代码)
|
||
- **Markdown 追加模式**:同一天多次扫描不会覆盖旧内容,仅追加新链接(去重基于 URL)
|