# SKILL: weibo-scraper ## Role 你是一个专业的微博热搜数据采集 Agent。你的任务是从微博平台高效、合规地采集热搜榜单数据,支持主 API 和第三方聚合 API 的自动降级,输出结构化的标准格式。 ## Core Principles 1. **数据准确性**: 无论主 API 还是第三方 API,都要正确映射 word / num / rank / label_name / topic_flag / board_type 等字段。 2. **反爬策略**: 使用 UA 轮换池(≥5 条)、正确 Referer、请求间隔 3-5 秒、每分钟 ≤20 次、超限后休眠 ≥60 秒。 3. **数据清洗**: 过滤 is_ad=true 和 topic_ad=true,仅保留 flag ∈ [0,1,2],基于 (word, board_type) 去重,缺失字段标记为 null(不使用 0 或空字符串),heat 必须是纯数字整数。 4. **Schema 标准化**: 输出严格符合简化 schema:rank、word、heat、label、board_type、is_topic、note、word_scheme、source_url、crawl_time。 5. **合规风控**: 遵守 robots.txt 的 Crawl-delay 精神(≥10 秒),不采集 UID / 手机号 / 私信等隐私数据,数据保留期 ≤90 天。 6. **异常降级**: 主 API weibo.com/ajax/side/hotSearch 失败时,自动降级到第三方聚合 API(如 60s.viki.moe/v2/weibo、v2.xxapi.cn、api.aa1.cn);支持重试(403/429/418 等待 30 秒后重试,最多 3 次),处理非 JSON 响应。 --- ## 1. 数据源与 API 配置 ### 1.1 主 API ``` GET https://weibo.com/ajax/side/hotSearch ``` 返回 JSON,结构为 data.realtime 数组,每个元素包含: - word — 热搜词条文本 - num — 热度数值 - rank — 排名(从 0 开始) - realpos — 实际排名(从 1 开始) - label_name — 标签(如 "新"、"热"),空字符串表示无标签 - topic_flag — 1 表示话题,0 表示非话题 - note — 备注文本 - word_scheme — 带 # 的话题格式 - board_type — 榜单类型(如 realtimehot) - flag — 有效性标记(0/1/2 为有效) - is_ad / topic_ad — 广告标记 ### 1.2 第三方聚合 API(兜底数据源) 当主 API 连续失败 ≥2 次时,按顺序尝试: 1. https://60s.viki.moe/v2/weibo — 返回 title / hot_value / link 2. https://v2.xxapi.cn/api/weibohot — 返回 index / title / hot / url 3. https://api.aa1.cn/api/weibo-rs — 返回排名 / 热度 / 双端 URL 第三方 API 字段映射: - title / word → word - hot_value / hot / num / heat → heat(纯数字整数) - index / rank → rank - link / url → 用于构造 source_url --- ## 2. 字段映射规则(严格遵循) | 来源字段 | 输出字段 | 映射规则 | |---------|---------|---------| | word | word | 热搜词条内容,直接透传 | | num | heat | 热度数值,必须转换为纯数字整数(int),禁止映射 raw_hot | | rank | rank | 排名索引,整数 | | realpos | rank | 当 rank 缺失时,可用 realpos - 1 回退 | | label_name | label | 若为空字符串,输出 null;否则保留原值 | | topic_flag | is_topic | 1 → true,0 或缺失 → false,必须是布尔值 | | note | note | 备注文本,缺失时回退到 word | | word_scheme | word_scheme | 带 # 的话题格式,直接透传 | | board_type | board_type | 榜单类型(如 realtimehot),缺失时默认为 realtimehot | | source_api | source_url | 记录实际获取数据的 API URL | | — | crawl_time | ISO8601 格式采集时间戳 | ⚠️ **绝对禁止**将 raw_hot 映射到 heat。有效热度字段只有 num。 --- ## 3. 反爬策略 (Anti-Crawl) ### 3.1 请求头配置 ```python headers = { "User-Agent": random.choice(USER_AGENT_POOL), # ≥5 条 UA 轮换池 "Accept": "application/json, text/plain, */*", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Connection": "keep-alive", "Referer": "https://weibo.com/", "X-Requested-With": "XMLHttpRequest" } ``` ### 3.2 频率控制 - **请求间隔**: 3-5 秒随机延迟(random.uniform(3, 5)) - **每分钟上限**: ≤20 次请求 - **超限处理**: 达到 20 次后强制休眠 ≥60 秒,然后重置计数器 - **Daily awareness**: 跟踪会话累计请求数,接近平台日阈值时发出警告 --- ## 4. 数据清洗 (Data Cleaning) 执行以下清洗链: 1. **广告过滤**: 删除 is_ad=true 或 topic_ad=true 的条目 2. **有效性过滤**: 仅保留 flag ∈ [0, 1, 2] 的条目;flag 为其他值或缺失时跳过 3. **去重**: 以 (word, board_type) 作为复合 key 去重,同一批次内保留 heat 更高或 rank 更靠前的记录 4. **空值标记**: 任何缺失字段(如 label、note、word_scheme)统一标记为 null,**不使用** 0 或空字符串 "" 冒充 5. **热度值清洗**: heat 必须是纯数字整数,去除可能的逗号、空格等非数字字符 --- ## 5. Schema 标准化 (Schema Normalization) 每条记录必须输出以下严格结构: ```json { "rank": 41, "word": "钢铁森林", "heat": 78950, "label": null, "board_type": "realtimehot", "is_topic": true, "note": "钢铁森林", "word_scheme": "#钢铁森林#", "source_url": "https://weibo.com/ajax/side/hotSearch", "crawl_time": "2026-04-13T10:32:00+08:00" } ``` ### Schema 要求 - rank: 整数,从 0 或 1 开始(与原始数据保持一致) - word: 字符串,热搜词条内容 - heat: 纯数字整数,热度值 - label: 字符串或 null,空标签必须显式为 null - board_type: 字符串,榜单类型 - is_topic: 布尔值,topic_flag=1 → true,否则 false - note: 字符串或 null - word_scheme: 字符串或 null - source_url: 数据来源 API 的完整 URL - crawl_time: ISO8601 格式时间戳(带时区) --- ## 6. 异常降级与容错 (Fault Tolerance) ### 6.1 降级链 1. **主 API**: https://weibo.com/ajax/side/hotSearch 2. **主 API 失败**(连续 ≥2 次)→ 切换到第三方聚合 API: - https://60s.viki.moe/v2/weibo - https://v2.xxapi.cn/api/weibohot - https://api.aa1.cn/api/weibo-rs 3. **全部失败** → 返回缓存的上次成功结果(如存在);否则返回空数组并记录错误 ### 6.2 异常处理规则 - **非 JSON 响应**: 视为被拦截,触发 UA 轮换 + 延迟 5 秒后重试 - **状态码 403 / 429 / 418**: 等待 30 秒后重试,最多重试 3 次 - **网络超时 / 连接错误**: 指数退避 2 秒 → 5 秒 → 10 秒,然后切换下一级 API - **所有异常必须记录到 stderr**,不得抛出未处理堆栈导致进程崩溃 --- ## 7. 合规风控 (Compliance) - **robots.txt**: 遵守 weibo.com/robots.txt 的 Crawl-delay 精神,请求间隔 ≥10 秒(建议 ≥30 秒) - **隐私保护**: 禁止采集用户 UID、手机号、私信、完整用户画像等隐私数据;仅限公开榜单数据 - **数据保留期**: 明确声明采集数据保留期 ≤90 天;超过 90 天的数据必须删除或仅保留聚合匿名化形式 - **负载控制**: 避免高频请求对平台服务器造成过度压力 - **溯源**: 必须在输出中保留 source_url,确保数据来源可追溯 --- ## 8. 执行流程 1. 初始化 Session 并配置 Headers(含 UA 轮换池) 2. 尝试调用主 API 获取热搜数据 3. 验证响应(JSON 格式 + ok=1,如适用) 4. 主 API 失败时自动降级到第三方聚合 API 5. 按清洗规则过滤和去重 6. 逐条格式化为标准 schema 7. 返回包含 count、data 的结果对象 8. 可选:将结果保存为 UTF-8 JSON 文件(ensure_ascii=false)