# Weibo Scraper Skill
## Identity
- **Name**: weibo_scraper
- **Version**: 1.8.0
- **Type**: Scraping/Data Extraction
- **Platform**: Weibo (weibo.com)
## Description
微博热点内容爬取技能。能够从微博平台爬取热搜榜、热门微博、热点话题等内容,提取结构化数据并进行清洗分类。**新增:详情页爬取 + 简报生成能力(强化反爬 + 备用方案 + 降级处理)**。
## Capabilities
1. **热搜榜爬取** - 获取微博热搜榜单 Top 50
2. **热门微博抓取** - 获取热门微博内容及作者信息
3. **详情页爬取** - 访问热点新闻详情页,提取完整正文内容 **强化反爬**
4. **图片提取** - 提取并保存微博配图 **增加备用方案**
5. **简报生成** - 将图文内容整理为 HTML/Markdown 简报 **增加降级处理**
6. **分类筛选** - 按娱乐、社会、科技、搞笑、体育、财经等分类
7. **指标提取** - 提取点赞数、评论数、转发数、阅读数
8. **数据清洗** - 去广告、去无效内容、格式标准化
9. **定时爬取** - 支持 Cron 定时任务和增量更新
10. **反爬合规** - UA轮换、频率控制、响应验证
## Methodology
### Step 1: 初始化请求环境
1. 创建 requests Session
2. 设置基础请求头 (User-Agent, Accept, Accept-Language, Referer)
3. 配置超时 (10秒)
### Step 2: 反爬合规控制
1. **User-Agent 轮换**: 准备 10+ 个常用 UA,每次请求随机选择
- Chrome (Mac/Windows/Linux) 各版本
- Safari (iOS/Mac)
- Firefox (Windows/Linux)
- 移动端 UA (Android/iOS)
2. **请求频率限制**: 每次请求间隔 5-10 秒随机延迟
3. **单 IP 限流**: 每分钟请求数 ≤ 10
4. **指数退避**: 遇到 429/403 时,等待 60s 后重试,再失败则等待 120s
5. **Cookie 维护**: 定期更新 Cookie,保持登录态
6. **请求头完整性**: 设置 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. **时间戳验证**: 确保数据时间戳 < 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: 详情页爬取 **强化反爬**
1. **获取详情页 URL**: 从热搜数据中提取 `mid` 或构建搜索详情 URL
2. **搜索 API 获取详情**: 使用 `https://m.weibo.cn/api/container/getIndex?containerid=100103type%3D1%26q%3D{keyword}` 获取微博详情
3. **解析正文内容**: 从返回的 JSON 中提取 `text` 字段(HTML 格式)
4. **提取纯文本**: 使用 strip_tags 或正则去除 HTML 标签获取纯文本
5. **内容截断处理**: 如果内容过长,保留前 5000 字符
6. **详情页反爬强化** **NEW**:
- Cookie 池维护:准备多个 Cookie,每 10 次请求轮换一次
- 代理 IP 支持:如果检测到 403/429,自动切换代理 IP
- 详情页专用退避:首次失败等待 15s,第二次等待 30s,第三次等待 60s
- 请求头强化:详情页请求额外添加 `X-Requested-With: XMLHttpRequest`
- 失败标记:如果连续 3 次失败,在 metadata 中标记 `详情页爬取: 部分失败`
7. **失败处理**: 详情页请求失败时记录日志,继续处理其他条目,不阻塞主流程
### Step 8: 图片提取 **增加备用方案**
1. **提取 pic_ids**: 从搜索 API 返回中获取 `pic_ids` 数组
2. **构建图片 URL**: 使用 `https://wx1.sinaimg.cn/large/{pic_id}.jpg` 格式
3. **图片尺寸选择**: 使用 large 尺寸减少水印干扰
4. **下载图片**: 如果需要保存图片,使用异步下载(并发 ≤ 3)
5. **设置 Referer**: 请求头设置 Referer 为 weibo.com 避免防盗链
6. **图片有效性验证**: 验证图片 URL 可访问
7. **图片提取备用方案** **NEW**:
- 备用来源1:media_urls 字段(有些 API 直接返回完整 URL)
- 备用来源2:从 text 字段的 HTML 中提取 ``
- 降级处理:如果所有图片 URL 都无效,在 media_urls 中保留空数组并记录
### Step 9: 简报生成 **增加降级处理**
1. **准备数据**: 整合标题、正文、图片、热度、分类等信息
2. **生成 Markdown 简报**:
- 使用 markdown 模板渲染
- 包含:基本信息、核心内容、互动数据、关联图片、原始链接
3. **生成 HTML 简报**(可选):
- 使用 HTML 模板渲染
- 包含 CSS 样式、图片画廊、时间线
4. **输出文件**: 保存为 `brief_{timestamp}.md` 或 `brief_{timestamp}.html`
5. **简报字段**:
- 基本信息: 发布时间、来源、热度排名
- 核心内容: 标题 + 正文(纯文本)
- 互动数据: 点赞、评论、转发、阅读
- 关联图片: Markdown/HTML 图片标签
- 原始链接: 详情页 URL
6. **简报降级处理** **NEW**:
- 内容缺失占位:如果正文为空,简报中显示 `(暂无详细内容)`
- 图片缺失占位:如果无图片,简报中显示 `(暂无图片)`
- 互动数据缺失:如果某项为 null,简报中显示 `--`
- Fallback 机制:如果 Markdown 生成失败,尝试生成纯文本简报
- 错误日志:记录简报生成过程中的错误,但不影响主流程
### Step 10: 结果输出
1. 保存到 workspace 目录
2. 打印执行结果摘要
## 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/api/container/getIndex?containerid=100103type%3D1%26q%3D{keyword}` - 无需 Cookie
- 用户微博: `https://weibo.com/ajax/statuses/mymblog?uid={uid}` - 需要登录
- 评论 API: `https://m.weibo.cn/comments/hotflow` - 需要登录
### Image URL Pattern
```python
# 基础 URL
BASE_IMAGE_URL = "https://wx1.sinaimg.cn/"
# 尺寸选项
SIZE_SMALL = "small" # 缩略图
SIZE_MIDDLE = "bmiddle" # 中图
SIZE_LARGE = "large" # 大图
SIZE_ORIGINAL = "mw690" # 原图
# 完整 URL 格式
image_url = f"https://wx1.sinaimg.cn/{SIZE}/{pic_id}.jpg"
```
### User-Agent Pool
```python
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"
]
```
### Rate Limiting
- 请求间隔: 5-10 秒随机
- 每分钟请求数: ≤ 10
- 超时重试: 3 次
- 退避策略: 遇到 403/429 等待 60s/120s 后重试
- **详情页请求间隔**: 8-12 秒(详情页更敏感)
- **详情页专用退避**: 首次失败等待 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
### Brief Generation Templates
#### Markdown 模板
```markdown
# 微博热点简报
## 基本信息
- 发布时间: {timestamp}
- 来源: {author_name} ({verified_status})
- 热度: 排名 {hot_rank} | 热度值 {hot_score}
## 核心内容
{title}
{content_text}
## 互动数据
- 点赞: {likes:,}
- 评论: {comments:,}
- 转发: {shares:,}
- 阅读: {read_count:,}
## 关联图片
{images_markdown}
## 原始链接
{detail_url}
---
*来源: 微博热搜榜 | 采集时间: {crawl_time}*
```
#### HTML 模板
```html