| name | aws-china-blog-archival-scan |
| description | Scan AWS China Blog historical articles beyond the 10-item RSS limit using HTML pagination. Covers 6+ months via /page/N/ URLs. |
| category | wiki |
AWS China Blog 历史文章归档扫描
Trigger
用户想通过 RSS 扫描 AWS China Blog 近半年文章,但 RSS 只推送最新 10 篇,无法覆盖。需要找替代方案。
核心发现
AWS China Blog 没有 sitemap 和完整 RSS 历史归档
- RSS feed (
https://aws.amazon.com/cn/blogs/china/feed/) 只含最新 10 篇
sitemap.xml → 404 不存在
- Google/Bing 搜索 API 均被反爬或返回不相关内容
site:aws.amazon.com/cn/blogs/china 搜索失败
正确的归档方案:HTML 分页
AWS China Blog 有完整的 /page/N/ 分页机制:
URL 模式:
- Page 1:
https://aws.amazon.com/cn/blogs/china/
- Page N:
https://aws.amazon.com/cn/blogs/china/page/N/(N ≥ 2)
每页文章数: 10 篇(规律)
分页上限: 44+ 页(持续增长)
近半年日期与分页对应关系
| 分页范围 | 日期范围 |
|---|
| Page 1–13 | 2026年1月–5月 |
| Page 14–22 | 2025年12月 |
| Page 23–28 | 2025年11月(6个月边界) |
| Page 29+ | 2025年10月更早 |
6个月覆盖: Page 1–28(约 278 篇,需去重)
抓取脚本
import urllib.request
import re
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'}
def get_articles(page):
url = "https://aws.amazon.com/cn/blogs/china/" if page == 1 else f"https://aws.amazon.com/cn/blogs/china/page/{page}/"
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req, timeout=15) as resp:
html = resp.read().decode('utf-8', errors='replace')
links = re.findall(r'href="(https://aws\.amazon\.com/cn/blogs/china/(?!author|category|feed|page/|facebook|twitter|linkedin)[^"?]+)"', html)
seen = set()
unique = []
for l in links:
if l not in seen:
seen.add(l)
unique.append(l)
return unique
for page in range(1, 29):
articles = get_articles(page)
print(f"Page {page}: {len(articles)} articles")
从 HTML 中提取日期(判断分页边界)
import re
iso_dates = re.findall(r'(2025-\d{2}-\d{2}|2026-\d{2}-\d{2})', html)
unique_dates = sorted(set(iso_dates))
关键坑
- blogwatcher-cli 有 Go HTTP 代理 bug:SOCKS 代理(127.0.0.1:10808)连接 loopback 时被拒绝,导致 scan 失败 → 用 Python urllib 绕过
- Bing RSS 格式搜索不返回 aws.amazon.com 结果:改用直接 HTML 分页爬取
- 每页 30 个 href 匹配但只有 10 篇文章:需要
seen set 去重
- 页面加载慢:每页 timeout 15s,扫描 28 页约需 2-3 分钟
Phase 1 评分:当 Jina Reader 返回 429 时的降级方案
Jina Reader API (r.jina.ai) 对批量请求返回 429 错误。改用 urllib 直接抓取 aws.amazon.com + heuristic scoring:
import urllib.request, re, time
PROXY = "http://127.0.0.1:10808"
def heuristic_score(title, slug, body_text):
"""value (1-10) × confidence (1-10),阈值 49 分通过"""
combined = (title + ' ' + slug).lower()
body_len = len(body_text) if body_text else 0
positive = [
('agentcore', 2.5), ('bedrock agentcore', 2.5), ('kiro', 2),
('claude code', 2), ('agentic', 2), ('multi-agent', 2),
('openclaw', 2), ('strands', 2), ('rag', 1.5),
('fine-tuning', 1.5), ('reinforcement learning', 2), ('rlhf', 2),
('context engineering', 2.5), ('memory', 1.5), ('evaluation', 1.5),
('browser', 1), ('mcp server', 2), ('serverless', 1),
('best practice', 1.5), ('case study', 1.5), ('deep dive', ),
(, ), (, ), (, ),
]
negative = [
(, -), (, -), (, -),
(, -), (, -), (, -),
(, -),
]
value =
kw, delta positive:
kw combined: value += delta
kw, delta negative:
kw combined: value += delta
body_len > : value +=
body_len < : value -=
confidence =
(k combined k [, , , ]):
confidence +=
combined:
confidence -=
(, (, value)), (, (, confidence))
阈值: value × confidence ≥ 49 → 送 Phase 2 入库
降级触发条件
- Jina Reader 返回 HTTP 429
- 或 Jina Reader 返回空/截断 body(<1KB)
抓取参数
- 每篇间隔 5s delay(避免触发 aws.amazon.com 限流)
- timeout 15-20s/page
- 并发 1(串行,非并发)
Phase 2 入库:sha256 + entity_type 前置要求
通过评分的文章入库前必须满足:
Raw article frontmatter
---
source_url: https://aws.amazon.com/cn/blogs/china/SLUG/
publish_date: YYYY-MM-DD
title: Article Title
review_value: 8
review_confidence: 8
review_recommendation: strong
tags: [aws-china-blog, ...]
sha256: <computed from body content>
---
sha256 计算: hashlib.sha256(body.encode('utf-8')).hexdigest()
- frontmatter 中先写 placeholder,body 提取后计算填入
- 用
patch 工具添加 sha256 字段
Entity frontmatter
---
title: Article Title
tags: [aws-china-blog, ...]
sources: [https://aws.amazon.com/cn/blogs/china/SLUG/]
entity_type: concept
review_value: 8
review_confidence: 8
review_recommendation: strong
publish_date: YYYY-MM-DD
---
必须包含 entity_type: concept。lint 对缺失 entity_type 的 entity 文件报错。
过滤策略:哪些文章要跳过
| 过滤条件 | 阈值 | 原因 |
|---|
| body 字符数 < 3000 | — | Thin article,无足够知识深度 |
| weekly roundup | 全部 | Digest 类,无独立论点 |
based-on- 前缀 | 全部 | 公式化套模板,无独特洞察 |
building-enterprise-rag-document-processing-platform-based-on-mineru | 全部 | MinerU 系列重复套用 |
| 已入库 slug | — | 查 ~/wiki/raw/articles/ 文件名去重 |
| score < 49 | — | heuristic 评分未达标 |
Index.md Total Pages 对齐
lint 报告的 actual count 优先级高于 header 声明值。
lint 的 countPages() 函数直接 walk 文件系统计数,比任何数学计算可靠。发现 drift 时:
- 跑
node scripts/wiki-lint.mjs 获取 actual count
- 用
sed -i '' 's/Total pages: OLD/Total pages: ACTUAL/' index.md 更新
不要用数学累加 — 每次入库后直接用 linter 输出覆盖 header。
输出
抓取后保存到 /tmp/aws_china_recent.txt,每行一个 URL,再与 wiki 已入库文章交叉对比,筛出未入库的文章进行 pipeline 评分。