#!/usr/bin/env python3 """ Weibo Scraper - 微博热点内容爬取工具 """ import json import time import requests from datetime import datetime from typing import Optional, List, Dict, Any import argparse import os import sys class WeiboScraper: """微博热点内容爬取器""" def __init__(self, config: Optional[Dict[str, Any]] = None): self.config = config or {} self.base_url = "https://weibo.com/ajax/side/hotSearch" self.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", "Accept": "application/json, text/plain, */*", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", "Referer": "https://weibo.com" } self.session = requests.Session() self.session.headers.update(self.headers) def get_hot_search(self, limit: int = 50) -> List[Dict[str, Any]]: """获取微博热搜榜""" try: response = self.session.get(self.base_url, timeout=10) if response.status_code == 200: data = response.json() if data.get("ok") == 1: return data.get("data", {}).get("realtime", [])[:limit] return [] except Exception as e: print(f"Error fetching hot search: {e}", file=sys.stderr) return [] def format_item(self, item: Dict[str, Any], category: str = "综合") -> Dict[str, Any]: """格式化单条热搜数据""" return { "source": { "platform": "weibo", "category": category, "hot_id": str(item.get("word_scheme", "")), "url": f"https://s.weibo.com/weibo?q={item.get('word', '')}" }, "engagement": { "likes": item.get("num", 0), "comments": 0, "shares": 0, "read_count": item.get("raw_hot", 0) }, "content": { "title": item.get("word", ""), "text": item.get("note", ""), "media_urls": [], "category_tags": [category] }, "author": { "username": "", "followers": 0, "verified": False }, "timestamp": datetime.now().isoformat(), "metrics": { "hot_rank": item.get("rank", 0), "hot_score": item.get("raw_hot", 0), "trend": "up" if item.get("label_name") else "stable" } } def scrape(self, category: str = "综合", limit: int = 50) -> Dict[str, Any]: """执行爬取""" items = self.get_hot_search(limit) results = [] for item in items: if item.get("flag", 0) in [1, 2]: # 有效数据 # 根据关键词判断分类 category = self._detect_category(item.get("word", "")) results.append(self.format_item(item, category)) return { "success": True, "timestamp": datetime.now().isoformat(), "count": len(results), "data": results } def _detect_category(self, keyword: str) -> str: """根据关键词检测分类""" keyword = keyword.lower() categories = { "娱乐": ["明星", "演员", "歌手", "电影", "电视剧", "综艺", "演唱会", "恋情", "结婚", "离婚", "分手"], "社会": ["事件", "新闻", "事故", "疫情", "政策", "法律", "民生"], "科技": ["手机", "电脑", "AI", "互联网", "数码", "科技", "发布会"], "搞笑": ["搞笑", "段子", "视频", "搞笑", "沙雕", "幽默"], "体育": ["足球", "篮球", "NBA", "世界杯", "奥运", "比赛", "冠军"], "财经": ["股票", "基金", "经济", "财经", "房价", "油价"] } for cat, keywords in categories.items(): if any(kw in keyword for kw in keywords): return cat return "综合" def save_results(data: Dict[str, Any], output_path: str): """保存结果到文件""" os.makedirs(os.path.dirname(output_path), exist_ok=True) with open(output_path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) def main(): parser = argparse.ArgumentParser(description="微博热点内容爬取工具") parser.add_argument("--category", type=str, default="综合", help="分类筛选") parser.add_argument("--limit", type=int, default=50, help="爬取数量限制") parser.add_argument("--output", type=str, default="workspace/weibo_output.json", help="输出文件路径") parser.add_argument("--cron", action="store_true", help="定时模式(仅输出不打印)") args = parser.parse_args() scraper = WeiboScraper() result = scraper.scrape(category=args.category, limit=args.limit) if args.cron: output_path = args.output else: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"workspace/weibo_{timestamp}.json" save_results(result, output_path) if not args.cron: print(json.dumps(result, ensure_ascii=False, indent=2)) else: print(f"Saved to {output_path}") if __name__ == "__main__": main()