# sreweekly.py SRE Weekly 抓取与文章提取脚本。单文件、无外部服务依赖,专为 n8n 定时任务设计:脚本自身**只负责抓取与落盘**,不发送邮件、不推送通知。 ## 功能概览 - 通过 RSS (`https://sreweekly.com/feed/`) 扫描新一期 SRE Weekly - **回溯抓取历史期刊**(RSS 只暴露最近 ~10 期,`--backfill` 直接走站点 URL 抓任意老期) - 把每期 `content:encoded` 原样保存为 HTML - 解析出每期的所有文章条目(标题 / 链接 / 简介 / 引用 / 作者) - 用 [`trafilatura`](https://github.com/adbar/trafilatura) 抓文章原文并转 Markdown - 用 `manifest.json` 记录每期状态,避免重复处理 - 每篇文章生成一个独立 `.md` 文件,含 feed 简介 + 抓取的正文 ## 安装依赖 ```bash pip3 install feedparser trafilatura ``` `trafilatura` 仅在抓文章正文时才必需;若加 `--skip-fetch` 只用 feed 简介,可省略。 ## 目录结构 默认工作目录 `~/Workspace/nexus/sreweekly/`(可用 `--dir` 覆盖): ``` sreweekly/ ├── manifest.json # 状态记录 ├── html/-<日期>.html # 每期原始 HTML(feed 版 或 backfill 站点整页) ├── pages/.html # backfill 抓到的站点整页缓存 ├── articles// # 每篇文章原始 HTML 缓存 + index.json 抓取日志 │ ├── 01-.html │ └── index.json └── markdown// # 每期文章的 markdown 输出 ├── 01-.md └── 02-.md ``` ## 用法 ```bash # 扫描 feed,新增期落盘并登记 manifest python3 sreweekly.py # 只探测有无新期(供 n8n 分支判断),输出 NEW:533,532 或 NONE python3 sreweekly.py --check # 提取指定期文章为 markdown(默认联网抓正文) python3 sreweekly.py --extract 533 python3 sreweekly.py --extract latest # 最新一期 python3 sreweekly.py --extract pending # 所有未提取的期(n8n 每日推荐) python3 sreweekly.py --extract all # 全部(配合 --force 覆盖) # 查看状态 python3 sreweekly.py --status python3 sreweekly.py --issues # 回溯抓取历史期刊(绕过 RSS 只有最近 ~10 期的限制) python3 sreweekly.py --backfill 430..533 # 抓期号 430 到 533 之间所有未登记的期 python3 sreweekly.py --backfill 1..533 # 全站回溯(500+ 期,约 12-15 分钟) python3 sreweekly.py --backfill 450 # 只抓单期 # 回溯完再走标准提取流程: python3 sreweekly.py --extract pending ``` ## 选项 | 选项 | 说明 | | --- | --- | | `--feed URL` | RSS 地址,默认 `https://sreweekly.com/feed/` | | `--dir PATH` | 工作目录,默认 `~/Workspace/nexus/sreweekly/` | | `--force` | 重新提取已提取过的期,覆盖旧 markdown | | `--skip-fetch` | 不抓文章正文,只使用 feed 简介 | | `--force-fetch` | 忽略 `articles/` / `pages/` 本地缓存,重新联网抓 HTML | | `--sleep 秒数` | 每次抓取间隔(默认 `1.5`,`--backfill` 也遵守此参数) | ## 典型 n8n 流程 1. **Cron 触发** → `python3 sreweekly.py --check` 2. 判断输出:`NEW:...` 走后续,`NONE` 结束 3. `python3 sreweekly.py`(扫描落盘新期) 4. `python3 sreweekly.py --extract pending`(抓正文 + 生成 markdown) 5. 下游节点读取 `markdown//*.md` 汇总成邮件/推送 ## Markdown 输出示例 每篇文章一个 `.md` 文件: ```markdown # 文章标题 - **期号**: SRE Weekly Issue #533(2024-05-20) - **作者**: Jane Doe - **链接**: https://example.com/post ## 简介 (来自 feed 的原始描述与引用) ## 正文 (trafilatura 抽取的原文 markdown;失败时显示错误信息) ``` ## Manifest 字段 `manifest.json` 中每期条目字段: | 字段 | 含义 | | --- | --- | | `id` / `title` / `url` / `pub_date` | 期号、标题、原文链接、发布日期 | | `html_file` | 落盘 HTML 相对路径 | | `fetched_at` / `extracted_at` | 抓取与提取时间戳 | | `extracted` | 是否已提取为 markdown | | `article_count` | 该期文章数 | | `markdown_dir` | markdown 输出目录(相对) | | `articles_fetched` / `articles_failed` | 正文抓取成功/失败数 | | `source` | 数据来源标记:`backfill` 表示由 `--backfill` 从站点整页抓取(feed 抓取无此字段) | ## 故障排查 - **feed 抓取失败或为空**:检查 `--feed` 网络可达性,或 feed 结构变更 - **`trafilatura returned empty`**:某些站点反爬/JS 渲染,正文段落会写入错误提示但不影响其它文章 - **重跑某期**:`--extract --force`;重新联网抓正文再加 `--force-fetch` - **回溯抓不到某期**:脚本会打印 `⚠️ # 抓取失败:...` 并继续下一期,最后汇总失败期号;对失败期号单独 `--backfill --force-fetch` 重试即可 - **回溯抓到的期日期显示当天**:说明页面 `` 结构变了,`extract_pub_date_from_page` 未命中,会 fallback 到今天——不影响提取,但排序会乱