Skill: freedompixels/multi-platform-trend (version 1.2.5)

--- slug: multi-platform-trend name: 多平台热点聚合 version: "1.0.0" author: 千策 --- # 多平台热点聚合 一站式抓取中国主流平台实时热点，返回结构化数据供后续分析使用。 ## 核心能力 1. **多平台抓取** — 知乎热榜、微博热搜、百度热搜、B站排行榜 2. **热度数据** — 获取每个热点的热度值和排名 3. **按平台/关键词过滤** — 支持按平台或关键词筛选 4. **结构化JSON输出** — 便于后续AI分析或程序处理 ## 快速开始 用户说"今天什么热点"时： ``` 1. 运行 python3 scripts/fetch_trends.py --all 2. 呈现各平台热点列表 3. 用户选择感兴趣的热点 4. 将热点标题发给 AI 进行选题分析和内容创作 ``` ## 支持平台 | 平台 | 数据源 | 更新速度 | |------|--------|----------| | 知乎热榜 | api.zhihu.com | 实时 | | 微博热搜 | weibo.com/ajax | 实时 | | 百度热搜 | top.baidu.com | 实时 | | B站排行榜 | api.bilibili.com | 每日 | ## 使用方式 ### 查看所有平台热点 ```bash python3 scripts/fetch_trends.py --all --limit 20 ``` ### 查看单平台 ```bash python3 scripts/fetch_trends.py --platform zhihu --limit 10 python3 scripts/fetch_trends.py --platform weibo --limit 10 python3 scripts/fetch_trends.py --platform baidu --limit 10 python3 scripts/fetch_trends.py --platform bilibili --limit 10 ``` ### 按关键词过滤 ```bash python3 scripts/fetch_trends.py --all --keyword "AI" python3 scripts/fetch_trends.py --all --keyword "科技" ``` ### JSON 输出（供程序处理） ```bash python3 scripts/fetch_trends.py --all --json ``` ## 输出格式 ### 文字报告 ``` 📊 今日热点速览（2026-04-19） 🔥 知乎 | 15 条 1. 追觅科技砸2亿年薪招首席科学家 🔥152万 2. OpenAI发布新模型 🔥98万 ... 🔥 微博 | 15 条 1. [热]明星官宣新恋情 🔥850万 ... ``` ### JSON 输出（推荐用于程序处理） ```bash python3 scripts/fetch_trends.py --all --json ``` 返回字段：title / platform / heat / heat_display / url / category / excerpt ## 后续处理建议 获取热点列表后，用户可将标题和摘要复制给 AI 进行选题分析和内容创作。Skill本身只负责数据抓取，不包含自动分析功能。 ## 配置项 | 配置 | 说明 | 默认值 | |------|------|--------| | 监控平台 | 抓取哪些平台 | 知乎+微博+百度 | | 过滤关键词 | 只看哪些领域 | 无（全部） | | 抓取数量 | 每个平台取几条 | 15条 | ## 文件结构 ``` multi-platform-trend/ ├── SKILL.md # 本文件 ├── scripts/ │ ├── fetch_trends.py # 热点抓取脚本 │ └── config.json # 用户配置（运行时生成） └── assets/ # 评分参考文件（可选） ``` ## 与其他 Skill 的配合 - **cn-auto-publisher**：热点分析后，生成内容可交给 cn-auto-publisher 发布到知乎/小红书 - **rss-content-flow**：热点 + RSS = 完整内容来源 ## 注意事项 - API 请求设置合理的超时（10秒），失败时自动跳过 - 微博热搜需要 User-Agent 伪装，已在脚本中处理 - 热度数据为估算值，仅供参考 - 本 Skill 只负责热点数据抓取，不包含选题分析和内容生成功能

path: README.md
content: # multi-platform-trend

多平台热点聚合与选题分析。一站式抓取知乎热榜、微博热搜、百度热搜等中国主流平台实时热点，AI 分析热度趋势并推荐最佳选题方向。

## 功能

- 🔥 **多平台抓取** — 知乎热榜、微博热搜、百度热搜、B站排行榜
- 🏷️ **智能分类** — AI 自动按领域分类（科技、商业、社会、娱乐等）
- 📊 **选题评分** — 评估每个热点的「内容机会值」（热度×契合度×竞争窗口）
- 💡 **选题推荐** — 根据创作者定位推荐最适合写作的热点
- ⏰ **定时监控** — 每日定时抓取，新热点即时提醒

## 使用方法

### 触发词
"今天什么热点"、"帮我看看热搜"、"找选题"、"知乎热榜"、"微博热搜"、"热搜分析"

### 查看所有平台热点
```bash
python3 scripts/fetch_trends.py -p all -n 20
```

### 查看单平台
```bash
python3 scripts/fetch_trends.py -p zhihu -n 10
python3 scripts/fetch_trends.py -p weibo -n 10
```

### 按关键词过滤
```bash
python3 scripts/fetch_trends.py -p all -k "AI"
python3 scripts/fetch_trends.py -p all -k "科技"
```

### 输出示例
```
📊 今日热点速览

🔥 知乎 | 30 条
  1. 警方通报全红婵遭网暴案  🔥1065万热度
  2. 小米食堂发布「小米」冰激凌  🔥207万热度
  3. 追觅科技砸2亿年薪招首席科学家  🔥152万热度

🔥 微博 | 10 条
  1. 男子微信群多次侮辱全红婵被拘  🔥413926
  2. 这些品牌竟然都是假洋牌  🔥292902
```

## 支持平台

| 平台 | 状态 | 数据量 | 更新速度 |
|------|------|--------|----------|
| 知乎热榜 | ✅ 稳定 | Top 50 | 实时 |
| 微博热搜 | ✅ 稳定 | Top 50 | 实时 |
| 百度热搜 | ⚠️ 部分可用 | Top 50 | 实时 |
| B站排行榜 | ⚠️ 部分可用 | Top 100 | 每日 |

## AI 选题分析工作流

```
热点数据抓取
    ↓
AI 领域分类（科技/商业/社会/娱乐/教育）
    ↓
内容机会评分（0-100分）
  - 🔥 热度分 30%
  - 🎯 契合度 30%
  - ⏰ 时效窗口 20%
  - 📝 竞争度 20%
    ↓
Top 5 选题推荐
  - 写作角度建议
  - 建议发布平台
  - 预估阅读量区间
```

## 与其他 Skill 配合

- **rss-content-flow**：热点（实时） + RSS（深度） = 完整内容来源
- **social-media-poster**：选题确定后直接发布
- **content-creator**：选题 → 生成 → 发布完整链路
- **feishu-daily-report**：热点分析纳入日报

## 系统要求

- Python 3.8+
- 可访问知乎/微博 API（部分环境需要代理）

## License

MIT


path: scripts/fetch_trends.py
content: #!/usr/bin/env python3
"""
多平台热点聚合抓取引擎
支持：知乎热榜、微博热搜、百度热搜、B站排行榜

用法:
  python3 fetch_trends.py --all --limit 20
  python3 fetch_trends.py --platform zhihu --limit 10
  python3 fetch_trends.py --all --keyword "AI" --json
"""

import json
import os
import sys
import ssl
import argparse
import time
import certifi
from urllib.request import urlopen, Request
from urllib.error import URLError, HTTPError

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))

# SSL 配置：优先标准验证，失败才降级
# macOS Python 需要显式加载 certifi 根证书
_SAFE_SSL_CTX = ssl.create_default_context()
_SAFE_SSL_CTX.load_verify_locations(certifi.where())

def _urlopen(req, timeout=10):
    """优先标准SSL，失败自动降级"""
    try:
        return urlopen(req, timeout=timeout, context=_SAFE_SSL_CTX)
    except URLError as e:
        # SSL证书验证失败时降级到certifi
        reason = getattr(e, 'reason', None)
        if isinstance(reason, (ssl.SSLError, ssl.SSLCertVerificationError)):
            fallback_ctx = ssl.create_default_context()
            fallback_ctx.load_verify_locations(certifi.where())
            return urlopen(req, timeout=timeout, context=fallback_ctx)
        raise
    except Exception as e:
        # 其他SSL错误也尝试降级
        if 'SSL' in str(type(e).__name__) or 'SSL' in str(e):
            fallback_ctx = ssl.create_default_context()
            fallback_ctx.load_verify_locations(certifi.where())
            return urlopen(req, timeout=timeout, context=fallback_ctx)
        raise

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/120.0.0.0 Safari/537.36"
}

# ========== 知乎热榜 ==========

def fetch_zhihu(limit=20):
    """抓取知乎热榜"""
    url = "https://api.zhihu.com/topstory/hot-lists/total?limit={}".format(limit)
    try:
        req = Request(url, headers=HEADERS)
        with _urlopen(req, timeout=10) as resp:
            data = json.loads(resp.read().decode("utf-8"))
    except Exception as e:
        print("  ⚠️ 知乎热榜抓取失败: {}".format(e), file=sys.stderr)
        return []

    results = []
    for item in data.get("data", []):
        target = item.get("target", {})
        title = target.get("title", "").strip()
        if not title:
            continue

        # 提取热度数值
        detail = item.get("detail_text", "")
        heat_num = 0
        if "万" in detail:
            try:
                heat_num = float(detail.replace("万热度", "").replace("万", "").strip()) * 10000
            except ValueError:
                pass
        elif "热度" in detail:
            try:
                heat_num = int(detail.replace("热度", "").strip())
            except ValueError:
                pass

        results.append({
            "title": title,
            "platform": "知乎",
            "heat": int(heat_num),
            "heat_display": detail,
            "url": "https://www.zhihu.com/question/{}".format(target.get("id", "")),
            "category": "",
            "excerpt": (target.get("excerpt", "") or "")[:100]
        })

    return results


# ========== 微博热搜 ==========

def fetch_weibo(limit=20):
    """抓取微博热搜"""
    url = "https://weibo.com/ajax/side/hotSearch"
    headers = {**HEADERS, "Referer": "https://weibo.com/"}
    try:
        req = Request(url, headers=headers)
        with _urlopen(req, timeout=10) as resp:
            data = json.loads(resp.read().decode("utf-8"))
    except Exception as e:
        print("  ⚠️ 微博热搜抓取失败: {}".format(e), file=sys.stderr)
        return []

    results = []
    realtime = data.get("data", {}).get("realtime", [])
    for item in realtime[:limit]:
        note = item.get("note", "").strip()
        if not note:
            continue
        note = item.get("note", "").strip()
        if not note:
            continue

        label = item.get("label_name", "")
        if label:
            note = "[{}]{}".format(label, note)

        results.append({
            "title": note,
            "platform": "微博",
            "heat": int(item.get("num", 0)),
            "heat_display": str(item.get("num", 0)),
            "url": "https://s.weibo.com/weibo?q=%23{}%23".format(
                item.get("word", item.get("note", ""))
            ),
            "category": "",
            "excerpt": ""
        })

    return results


# ========== 百度热搜 ==========

def fetch_baidu(limit=20):
    """抓取百度热搜"""
    url = "https://top.baidu.com/api/board?platform=wise&tab=realtime"
    try:
        req = Request(url, headers=HEADERS)
        with _urlopen(req, timeout=10) as resp:
            data = json.loads(resp.read().decode("utf-8"))
    except Exception as e:
        print("  ⚠️ 百度热搜抓取失败: {}".format(e), file=sys.stderr)
        return []

    results = []
    cards = data.get("data", {}).get("cards", [])
    if cards:
        content = cards[0].get("content", [])
        for item in content[:limit]:
            query = item.get("query", "").strip()
            if not query:
                continue

            desc = item.get("desc", "")
            heat_num = 0
            try:
                heat_num = int(item.get("hotScore", 0))
            except (ValueError, TypeError):
                pass

            results.append({
                "title": query,
                "platform": "百度",
                "heat": heat_num,
                "heat_display": desc[:30] if desc else "",
                "url": "https://www.baidu.com/s?wd={}".format(query),
                "category": item.get("tag", ""),
                "excerpt": desc[:100] if desc else ""
            })

    return results


# ========== B站排行榜 ==========

def fetch_bilibili(limit=20):
    """抓取B站排行榜"""
    url = "https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=all"
    try:
        req = Request(url, headers=HEADERS)
        with _urlopen(req, timeout=10) as resp:
            data = json.loads(resp.read().decode("utf-8"))
    except Exception as e:
        print("  ⚠️ B站排行榜抓取失败: {}".format(e), file=sys.stderr)
        return []

    results = []
    items = data.get("data", {}).get("list", [])
    for item in items[:limit]:
        title = item.get("title", "").strip()
        if not title:
            continue

        stat = item.get("stat", {})
        results.append({
            "title": title,
            "platform": "B站",
            "heat": int(stat.get("view", 0)),
            "heat_display": "{}播放".format(_format_num(stat.get("view", 0))),
            "url": item.get("short_link_v2", "https://www.bilibili.com/video/{}".format(
                item.get("bvid", "")
            )),
            "category": item.get("tname", ""),
            "excerpt": item.get("description", "")[:100] if item.get("description") else ""
        })

    return results


# ========== 工具函数 ==========

def _format_num(n):
    """格式化数字"""
    n = int(n)
    if n >= 10000:
        return "{:.1f}万".format(n / 10000)
    elif n >= 1000:
        return "{:.1f}k".format(n / 1000)
    return str(n)


def filter_by_keyword(items, keyword):
    """按关键词过滤"""
    kw = keyword.lower()
    return [item for item in items if kw in item["title"].lower()]


def print_report(items, keyword=None):
    """打印热点报告"""
    if not items:
        print("\n📭 未抓取到热点数据")
        return

    # 按平台分组
    by_platform = {}
    for item in items:
        p = item["platform"]
        by_platform.setdefault(p, []).append(item)

    print("\n" + "=" * 60)
    if keyword:
        print("📊 热点速览 | 关键词: 「{}」".format(keyword))
    else:
        print("📊 今日热点速览")
    print("=" * 60)

    for platform, topics in by_platform.items():
        print("\n🔥 {} | {} 条".format(platform, len(topics)))
        for i, t in enumerate(topics, 1):
            heat = t.get("heat_display", "")
            if heat:
                print("  {}. {}  🔥{}".format(i, t["title"][:48], heat))
            else:
                print("  {}. {}".format(i, t["title"][:48]))
            if t.get("excerpt"):
                print("     {}".format(t["excerpt"][:60]))

    print("\n" + "-" * 60)
    print("💡 AI 分析：输入「分析选题」获取内容机会评分")
    print("💡 输入「生成内容」直接改写为知乎/小红书文案")


# ========== 主入口 ==========

FETCHERS = {
    "zhihu": fetch_zhihu,
    "weibo": fetch_weibo,
    "baidu": fetch_baidu,
    "bilibili": fetch_bilibili,
}

PLATFORM_NAMES = {
    "zhihu": "知乎",
    "weibo": "微博",
    "baidu": "百度",
    "bilibili": "B站",
    "all": "全部平台",
}


def main():
    parser = argparse.ArgumentParser(description="多平台热点聚合")
    parser.add_argument("--platform", "-p",
                        choices=list(FETCHERS.keys()) + ["all"],
                        default="all",
                        help="抓取平台（默认全部）")
    parser.add_argument("--limit", "-n", type=int, default=15,
                        help="每个平台抓取条数（默认15）")
    parser.add_argument("--keyword", "-k",
                        help="按关键词过滤")
    parser.add_argument("--json", action="store_true",
                        help="输出 JSON 格式")
    args = parser.parse_args()

    # 确定要抓取的平台
    if args.platform == "all":
        platforms = list(FETCHERS.keys())
    else:
        platforms = [args.platform]

    # 依次抓取
    all_items = []
    for name in platforms:
        display_name = PLATFORM_NAMES.get(name, name)
        print("📡 抓取 {}...".format(display_name), file=sys.stderr)
        start = time.time()
        items = FETCHERS[name](args.limit)
        elapsed = time.time() - start
        if items:
            print("  ✅ {} 条 ({:.1f}s)".format(len(items), elapsed), file=sys.stderr)
        else:
            print("  ⚠️ 无数据 ({:.1f}s)".format(elapsed), file=sys.stderr)
        all_items.extend(items)

    # 关键词过滤
    if args.keyword:
        all_items = filter_by_keyword(all_items, args.keyword)

    # 按热度排序
    all_items.sort(key=lambda x: x.get("heat", 0), reverse=True)

    # 输出
    if args.json:
        print(json.dumps(all_items, ensure_ascii=False, indent=2))
    else:
        print_report(all_items, args.keyword)


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)