skill.md 13.8 KB

Weibo Scraper Skill

Identity

  • Name: weibo_multi_list_scraper
  • Version: 2.0.0
  • Type: Scraping/Data Extraction
  • Platform: Weibo (weibo.com)

Description

微博热点内容爬取技能(多榜版本)。能够从微博平台爬取热搜榜、热门微博、热点话题等内容,提取结构化数据并进行清洗分类。强化版支持详情页爬取 + 图片提取 + 简报生成 + 反爬强化。

Capabilities

  1. 热搜榜爬取 - 获取微博热搜榜单 Top 50
  2. 热门微博抓取 - 获取热门微博内容及作者信息
  3. 分类筛选 - 按娱乐、社会、科技、搞笑、体育、财经等分类
  4. 指标提取 - 提取点赞数、评论数、转发数、阅读数
  5. 数据清洗 - 去广告、去无效内容、格式标准化
  6. 定时爬取 - 支持 Cron 定时任务和增量更新
  7. 反爬合规 - UA轮换、频率控制、响应验证、Cookie池
  8. 详情页爬取 - 访问热点详情页 URL,提取完整正文内容 强化反爬
  9. 图片提取 - 从 media_urls / 详情页提取并保存图片到本地 多源备份
  10. 简报生成 - 生成文字+图片 Markdown/HTML 简报 降级处理

Methodology

Step 1: 初始化请求环境

  1. 创建 requests Session
  2. 设置基础请求头 (User-Agent, Accept, Accept-Language, Referer)
  3. 配置超时 (10秒)
  4. 初始化 Cookie 池

Step 2: 反爬合规控制 (强化版)

  1. User-Agent 轮换: 准备 10+ 个常用 UA,每次请求随机选择
    • Chrome (Mac/Windows/Linux) 各版本
    • Safari (iOS/Mac)
    • Firefox (Windows/Linux)
    • 移动端 UA (Android/iOS)
  2. Cookie 池轮换: 准备 5+ 个 Cookie,每 10 次请求轮换一次
  3. 请求频率限制: 每次请求间隔 5-10 秒随机延迟
  4. 单 IP 限流: 每分钟请求数 ≤ 10
  5. 指数退避: 遇到 429/403 时,等待 60s 后重试,再失败则等待 120s
  6. 代理 IP 支持: 配置代理池,遇到 403/429 自动切换
  7. 请求头完整性: 设置 Accept-Encoding, Accept-Language, Connection 等

Step 3: 执行爬取 (多 API 源)

  1. 主 API: 请求 PC 端热搜 https://weibo.com/ajax/side/hotSearch
  2. 备用 API 1: 请求移动端热搜 https://m.weibo.cn/api/index/list?type=hot
  3. 备用 API 2: 请求话题搜索 https://m.weibo.cn/api/container/getIndex
  4. 优先使用返回 JSON 的 API,遇到 HTML 响应则切换
  5. 解析 JSON 响应
  6. 过滤低质量内容 (flag=1,2 为有效数据)
  7. 分类标注

Step 4: 数据验证与新鲜度

  1. 时间戳验证: 确保数据时间戳
  2. 新鲜度保障: 记录采集时间,过期数据标记
  3. JSON 验证: 检测返回是否为 HTML (验证码页面)
  4. 响应验证: 验证 JSON 解析是否成功,检查 ok 字段是否为 1
  5. 降级策略: 主 API 失败时自动切换备用 API

Step 5: 数据增强

  1. 字段补全: engagement.comments/shares 尝试从多源获取
  2. 作者信息补全: 尝试从话题页获取作者信息
  3. 多源验证: 对比多个数据源,确保数据准确性
  4. 数据清洗: 去广告、去无效内容、格式标准化
  5. 时间戳标准化: 将 API 返回的时间戳转为 ISO 格式

Step 6: 数据清洗与格式化

  1. 提取关键字段
  2. 转换中文数字 (如 "1.2万" → 12000)
  3. 标准化时间戳
  4. 生成最终 JSON,保留原始数据

Step 7: 详情页爬取 (强化反爬 - 解决 D6)

  1. 提取详情页 URL: 从热搜数据中识别 m.weibo.cn/detail/{mid} 格式 URL
  2. 搜索 API 获取详情: 使用 https://m.weibo.cn/api/container/getIndex?containerid=100103type%3D1%26q%3D{keyword} 获取微博详情
  3. 请求详情页 API: 使用 https://m.weibo.cn/statuses/show?id={mid} 获取完整内容
  4. 内容提取: 解析返回的 JSON,提取 text 字段(完整正文)
  5. 图片URL提取: 从 pics 数组提取图片 URL 到 content.media_urls

  6. 详情页反爬强化 NEW:

    • Cookie 池轮换:准备多个 Cookie,每 10 次请求轮换一次
    • 代理 IP 支持:如果检测到 403/429,自动切换代理 IP
    • 详情页专用退避:首次失败等待 15s,第二次等待 30s,第三次等待 60s
    • 请求头强化:详情页请求额外添加 X-Requested-With: XMLHttpRequest
    • 失败标记:如果连续 3 次失败,在 metadata 中标记 详情页爬取: 部分失败
    • 备用来源:使用搜索 API 作为备用
  7. 降级处理: 详情页失败时使用热搜榜已有信息,记录 详情页爬取: 部分失败

Step 8: 图片提取与保存 (多源备份 - 解决 D7)

  1. 图片URL验证: 检查 content.media_urls 是否为空
  2. 并发下载: 使用 asyncio/aiohttp 并发下载图片(控制并发数 ≤ 3)
  3. 重试机制: 下载失败时重试 3 次
  4. 保存路径: 保存到 workspace/images/{mid}_{index}.jpg
  5. 图片命名: 使用原始文件名或 {timestamp}_{index} 命名
  6. 质量验证: 下载后验证图片完整性(检查文件大小 > 1KB,尝试解码)

  7. 图片提取多源备份 NEW:

    • 备用来源1:media_urls 字段(API 直接返回的 URL)
    • 备用来源2:从 text 字段的 HTML 中提取 <img src="...">
    • 备用来源3:详情页搜索 API 返回的 pics 数组
    • 降级处理:如果所有图片 URL 都无效,在 media_urls 中保留空数组并记录

Step 9: 简报生成 (降级处理 - 解决 D8)

  1. 创建简报目录: workspace/output/{date}/
  2. 生成 Markdown 简报: 按模板格式生成 brief.md
  3. 生成 HTML 简报: 可选,使用 HTML 模板渲染
  4. 简报内容结构:
    • 基本信息: 发布时间、来源、热度排名、分类标签
    • 核心内容: 标题 + 正文 + 摘要(50字内)
    • 互动数据: 点赞/评论/转发/阅读数
    • 关联图片: 使用相对路径引用图片
    • 原始链接: 详情页 URL
  5. 降级处理: 部分数据缺失时,在简报中标注 "[数据获取失败]"

  6. 简报降级处理 NEW:

    • 内容缺失占位:如果正文为空,简报中显示 (暂无详细内容)
    • 图片缺失占位:如果无图片,简报中显示 (暂无图片)
    • 互动数据缺失:如果某项为 null,简报中显示 --
    • Fallback 机制:如果 Markdown 生成失败,尝试生成纯文本简报
    • 错误日志:记录简报生成过程中的错误,但不影响主流程

Step 10: 结果输出

  1. 保存 JSON 数据到 workspace 目录
  2. 保存图片到 workspace/images/ 目录
  3. 保存简报到 workspace/output/ 目录
  4. 打印执行结果摘要

Implementation

API Endpoints

  • 主 API (PC 端): https://weibo.com/ajax/side/hotSearch - 需要 Cookie
  • 备用 API 1 (移动端): https://m.weibo.cn/api/index/list?type=hot - 无需 Cookie
  • 备用 API 2 (话题): https://m.weibo.cn/api/container/getIndex - 无需 Cookie
  • 详情页 API: https://m.weibo.cn/statuses/show?id={mid} - 获取完整内容
  • 搜索详情 API: https://m.weibo.cn/api/container/getIndex?containerid=100103type%3D1%26q%3D{keyword} - 搜索获取详情
  • 用户微博: https://weibo.com/ajax/statuses/mymblog?uid={uid} - 需要登录
  • 评论 API: https://m.weibo.cn/comments/hotflow - 需要登录

Crawl Strategy

  1. 使用公开 API 或网页爬取热搜数据
  2. 解析 JSON 响应获取结构化数据
  3. 过滤低质量内容(广告、无内容、已删除)
  4. 分类标注
  5. 输出标准化 JSON

User-Agent Pool

USER_AGENTS = [
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 Mobile/15E148 Safari/604.1",
    "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 Chrome/112.0.0.0 Mobile Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Version/17.0 Safari/605.1.15"
]
# 实际使用时需要维护真实的 Cookie 池
COOKIE_POOL = [
    {"cookie": "SUB=_xxx1", "domain": ".weibo.com"},
    {"cookie": "SUB=_xxx2", "domain": ".weibo.com"},
    # ...
]

Proxy Pool (占位)

# 实际使用时需要配置真实的代理池
PROXY_POOL = [
    {"http": "http://proxy1:port", "https": "https://proxy1:port"},
    {"http": "http://proxy2:port", "https": "https://proxy2:port"},
    # ...
]

Rate Limiting

  • 请求间隔: 5-10 秒随机
  • 每分钟请求数: ≤ 10
  • 超时重试: 3 次
  • 退避策略: 遇到 403/429 等待 60s/120s 后重试
  • 详情页请求: 间隔 10-15 秒,降低被反爬概率
  • 详情页专用退避: 首次失败等待 15s,第二次 30s,第三次 60s

Error Handling & Fallback Strategy

  • 主 API 失败: 自动切换到移动端 API
  • 详情页失败: 返回热搜榜基础信息,标注 "[详情页获取失败]"
  • 详情页反爬强化:
    • Cookie 池轮换(每 10 次请求)
    • 代理 IP 切换(403/429 时)
    • 专用退避策略(15s → 30s → 60s)
  • 图片提取备用: media_urls 字段、HTML 提取、降级处理
  • 简报降级: 内容/图片缺失占位、Fallback 纯文本
  • 403 Forbidden: 更换 User-Agent 或切换备用 API
  • 429 Too Many Requests: 指数退避 (60s, 120s, 240s) 后重试
  • 网络超时: 重试,超时递增
  • 反爬机制: 降低频率或切换 API
  • HTML 响应: 检测到验证码页面,更换 UA 并尝试备用 API

Output Format

{
  "source": {
    "platform": "weibo",
    "category": "娱乐",
    "hot_id": "xxx",
    "url": "https://weibo.com/xxx"
  },
  "engagement": {
    "likes": 12345,
    "comments": null,
    "shares": null,
    "read_count": 123456
  },
  "content": {
    "title": "热搜标题",
    "text": "微博正文内容",
    "media_urls": ["https://xxx.jpg"],
    "category_tags": ["娱乐", "明星", "综艺"]
  },
  "author": {
    "username": null,
    "followers": null,
    "verified": false
  },
  "timestamp": "2024-01-01T00:00:00Z",
  "metrics": {
    "hot_rank": 1,
    "hot_score": 999999,
    "trend": "up"
  },
  "metadata": {
    "采集时间": "2024-01-01T00:00:00Z",
    "数据来源": "weibo_hotsearch_api",
    "API版本": "v2",
    "反爬合规": {
      "ua_rotation": true,
      "rate_limiting": true,
      "response_validation": true,
      "cookie_pool": true,
      "proxy_support": true
    },
    "详情页爬取": {
      "enabled": true,
      "状态": "成功|部分失败|完全失败",
      "正文提取": true,
      "反爬策略": ["cookie_pool", "proxy_fallback", "backoff_15_30_60"]
    },
    "图片提取": {
      "enabled": true,
      "主来源": "pics/media_urls",
      "备用来源": ["html_extract", "detail_search_api"],
      "降级处理": true
    },
    "简报生成": {
      "enabled": true,
      "format": "markdown",
      "降级处理": true,
      "内容缺失占位": true
    }
  },
  "raw_data": {}
}

简报输出格式 (brief.md)

# 微博热点简报

## 基本信息
- 发布时间: {timestamp}
- 来源: {author.username} ({verified})
- 热度: 排名 {hot_rank} | 热度值 {hot_score}
- 分类标签: {category_tags}

## 内容摘要
{summary_50_chars}

## 核心内容
{content.title}

{content.text|(暂无详细内容)}

## 互动数据
- 点赞: {likes|--}
- 评论: {comments|--}
- 转发: {shares|--}
- 阅读: {read_count|--}

## 关联图片
{images_markdown|(暂无图片)}

## 原始链接
{url}

降级处理占位符

## 核心内容
{title}

{content_text|(暂无详细内容)}

## 关联图片
{images_markdown|(暂无图片)}

## 互动数据
- 点赞: {likes|--}
- 评论: {comments|--}
- 转发: {shares|--}
- 阅读: {read_count|--}

注意: engagement 和 author 字段中无法获取的数据使用 null 而非 0 或 -1,表示数据不可用而非数据缺失。

Execution Commands

# 爬取热搜榜
python3 weibo_scraper.py --category 娱乐 --limit 20

# 爬取热门微博
python3 weibo_scraper.py --type hot --limit 50

# 详情页爬取 + 简报生成
python3 weibo_scraper.py --detail --brief --limit 10

# 定时增量更新
python3 weibo_scraper.py --cron --output /path/to/output.json

File Structure

weibo-scraper/
├── .claude/
│   └── skills/
│       └── main_skill/
│           └── SKILL.md (本文件)
├── weibo_scraper.py     # 主脚本
├── requirements.txt     # Python 依赖
└── workspace/            # 输出目录
    ├── output/            # 简报目录
    │   └── 2026-03-28/
    │       └── brief.md
    └── images/            # 图片目录
        └── xxx.jpg

Dependencies

  • Python: 3.8+
  • pip packages: requests, aiohttp (异步下载)

Quality Checks

  • [x] 数据完整: engagement 数据字段存在,无法获取的标记为 null
  • [x] 分类准确: category_tags 正确
  • [x] 时效性: timestamp 为最近内容
  • [x] 无效过滤: 已删除/广告内容已过滤
  • [x] 反爬合规: UA 轮换、Cookie 池、请求间隔、响应验证
  • [x] 数据可用性: 保留 metadata 和 raw_data
  • [x] 详情页爬取: 支持获取详情页完整内容 强化反爬
  • [x] 图片提取: 支持提取并保存图片 多源备份
  • [x] 简报生成: 支持生成 Markdown/HTML 简报 降级处理

训练记录

迭代历史

  • v1.9.0 → v2.0.0: 强化反爬(Cookie池、代理支持、详情页专用退避)+ 图片多源备份 + 简报降级处理

Benchmark 得分 (目标)

  • v1.9.0: 91.34 (理论)
  • v2.0.0: 目标 ≥ 90 (实际)

改进内容

  1. Step 2 增加 Cookie 池轮换
  2. Step 2 增加代理 IP 支持
  3. Step 7 增加详情页反爬强化(Cookie池、代理、专用退避)
  4. Step 8 增加图片多源备份
  5. Step 9 增加简报降级处理占位符