Download scripts/demo.py from aaroncxxx/a-share-analytics: direct link, hf CLI and curl.
- Browser
- Download file 11.8 kB
-
https://huggingface.co/aaroncxxx/a-share-analytics/resolve/main/scripts/demo.py
- Command line
-
hf download hf://aaroncxxx/a-share-analytics/scripts/demo.py
-
curl -L -o demo.py https://huggingface.co/aaroncxxx/a-share-analytics/resolve/main/scripts/demo.py
11.8 kB
| #!/usr/bin/env python3 | |
| """ | |
| A股微博热搜分析 Demo | |
| - 微博热搜抓取 | |
| - A股行情数据 | |
| - 热门讨论股票分析 | |
| """ | |
| import json | |
| import sys | |
| import urllib.request | |
| import urllib.error | |
| from datetime import datetime | |
| # ============================================================ | |
| # 1. 微博热搜抓取 | |
| # ============================================================ | |
| def fetch_weibo_hot(): | |
| """获取微博实时热搜""" | |
| url = "https://weibo.com/ajax/side/hotSearch" | |
| headers = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", | |
| "Accept": "application/json", | |
| "Referer": "https://weibo.com" | |
| } | |
| try: | |
| req = urllib.request.Request(url, headers=headers) | |
| with urllib.request.urlopen(req, timeout=10) as resp: | |
| data = json.loads(resp.read().decode("utf-8")) | |
| hot_list = data.get("data", {}).get("realtime", []) | |
| results = [] | |
| for item in hot_list[:50]: # 取前50 | |
| results.append({ | |
| "rank": item.get("rank", 0), | |
| "keyword": item.get("word", ""), | |
| "hot": item.get("num", 0), | |
| "category": item.get("category", ""), | |
| "label": item.get("label_name", ""), | |
| }) | |
| return results | |
| except Exception as e: | |
| print(f"⚠️ 微博热搜获取失败: {e}", file=sys.stderr) | |
| return [] | |
| def filter_stock_keywords(hot_list): | |
| """筛选A股相关关键词""" | |
| stock_keywords = [ | |
| "A股", "大A", "股市", "股票", "涨停", "跌停", "牛市", "熊市", | |
| "基金", "证券", "券商", "上证", "深证", "创业板", "科创板", | |
| "涨停板", "跌停板", "打板", "龙头", "妖股", "板块", | |
| "利好", "利空", "暴跌", "暴涨", "反弹", "回调", | |
| "北向资金", "主力", "游资", "散户", | |
| ] | |
| # 额外:提取可能的个股名称(2-4个汉字) | |
| stock_related = [] | |
| for item in hot_list: | |
| keyword = item["keyword"] | |
| # 精确匹配 | |
| for kw in stock_keywords: | |
| if kw in keyword: | |
| item["match_reason"] = f"包含「{kw}」" | |
| stock_related.append(item) | |
| break | |
| else: | |
| # 模糊匹配:包含"股"/"涨"/"跌"/"板" | |
| if any(w in keyword for w in ["股", "涨", "跌", "板", "牛市", "熊市", "基金"]): | |
| item["match_reason"] = "模糊匹配" | |
| stock_related.append(item) | |
| return stock_related | |
| # ============================================================ | |
| # 2. A股行情数据 (AKShare) | |
| # ============================================================ | |
| def fetch_market_overview(): | |
| """获取大盘指数""" | |
| try: | |
| import akshare as ak | |
| # 上证指数 | |
| sh = ak.stock_zh_index_daily(symbol="sh000001") | |
| sz = ak.stock_zh_index_daily(symbol="sz399001") | |
| cy = ak.stock_zh_index_daily(symbol="sz399006") | |
| def get_latest(df, name): | |
| last = df.iloc[-1] | |
| prev = df.iloc[-2] | |
| close = float(last["close"]) | |
| prev_close = float(prev["close"]) | |
| change_pct = (close - prev_close) / prev_close * 100 | |
| return { | |
| "name": name, | |
| "close": round(close, 2), | |
| "change_pct": round(change_pct, 2), | |
| } | |
| return [ | |
| get_latest(sh, "上证指数"), | |
| get_latest(sz, "深证成指"), | |
| get_latest(cy, "创业板指"), | |
| ] | |
| except Exception as e: | |
| print(f"⚠️ 大盘数据获取失败: {e}", file=sys.stderr) | |
| return [] | |
| def fetch_zt_dt(): | |
| """获取涨停/跌停数据""" | |
| try: | |
| import akshare as ak | |
| # 涨停板 | |
| zt_df = ak.stock_zt_pool_em(date=datetime.now().strftime("%Y%m%d")) | |
| zt_list = [] | |
| if zt_df is not None and not zt_df.empty: | |
| for _, row in zt_df.head(10).iterrows(): | |
| zt_list.append({ | |
| "code": str(row.get("代码", "")), | |
| "name": str(row.get("名称", "")), | |
| "change_pct": float(row.get("涨跌幅", 0)), | |
| "reason": str(row.get("涨停原因", "")), | |
| }) | |
| # 跌停板 | |
| dt_df = ak.stock_zt_pool_dtgc_em(date=datetime.now().strftime("%Y%m%d")) | |
| dt_list = [] | |
| if dt_df is not None and not dt_df.empty: | |
| for _, row in dt_df.head(10).iterrows(): | |
| dt_list.append({ | |
| "code": str(row.get("代码", "")), | |
| "name": str(row.get("名称", "")), | |
| "change_pct": float(row.get("涨跌幅", 0)), | |
| }) | |
| return {"涨停": zt_list, "跌停": dt_list} | |
| except Exception as e: | |
| print(f"⚠️ 涨停/跌停数据获取失败: {e}", file=sys.stderr) | |
| return {"涨停": [], "跌停": []} | |
| def fetch_hot_sectors(): | |
| """获取热门板块""" | |
| try: | |
| import akshare as ak | |
| df = ak.stock_board_industry_name_em() | |
| if df is not None and not df.empty: | |
| sectors = [] | |
| for _, row in df.head(10).iterrows(): | |
| sectors.append({ | |
| "name": str(row.get("板块名称", "")), | |
| "change_pct": float(row.get("涨跌幅", 0)), | |
| "leader": str(row.get("领涨股票", "")), | |
| }) | |
| return sectors | |
| return [] | |
| except Exception as e: | |
| print(f"⚠️ 板块数据获取失败: {e}", file=sys.stderr) | |
| return [] | |
| # ============================================================ | |
| # 3. 关联分析 | |
| # ============================================================ | |
| def analyze_correlation(hot_list, zt_dt, sectors): | |
| """分析热搜与行情的关联""" | |
| analysis = { | |
| "hot_stock_mentions": [], | |
| "potential_analysis": [], | |
| } | |
| # 提取热搜中提到的股票名称 | |
| stock_names_in_hot = [] | |
| for item in hot_list: | |
| keyword = item["keyword"] | |
| # 简单提取:如果关键词包含具体股票名(2-4字中文) | |
| if 2 <= len(keyword) <= 6 and not any(w in keyword for w in ["A股", "大A", "股市"]): | |
| stock_names_in_hot.append(keyword) | |
| analysis["hot_stock_mentions"] = stock_names_in_hot[:10] | |
| # 与涨停板交叉分析 | |
| zt_names = [item["name"] for item in zt_dt.get("涨停", [])] | |
| mentioned_and_zt = [name for name in stock_names_in_hot if name in zt_names] | |
| if mentioned_and_zt: | |
| analysis["potential_analysis"].append( | |
| f"🔥 以下股票同时出现在微博热搜和涨停板: {', '.join(mentioned_and_zt)}" | |
| ) | |
| # 板块分析 | |
| hot_sector_keywords = [item["keyword"] for item in hot_list if "板块" in item["keyword"]] | |
| if hot_sector_keywords: | |
| analysis["potential_analysis"].append( | |
| f"📊 热搜板块关键词: {', '.join(hot_sector_keywords)}" | |
| ) | |
| return analysis | |
| # ============================================================ | |
| # 4. 报告生成 | |
| # ============================================================ | |
| def generate_report(hot_list, stock_hot, market, zt_dt, sectors, correlation): | |
| """生成分析报告""" | |
| now = datetime.now().strftime("%Y-%m-%d %H:%M") | |
| lines = [] | |
| lines.append(f"📊 A股微博热搜分析报告") | |
| lines.append(f"⏰ {now}") | |
| lines.append("=" * 50) | |
| # 大盘概览 | |
| lines.append("") | |
| lines.append("📈 【大盘概览】") | |
| lines.append("-" * 40) | |
| if market: | |
| for m in market: | |
| arrow = "🔴" if m["change_pct"] < 0 else "🟢" | |
| lines.append(f" {arrow} {m['name']}: {m['close']} ({m['change_pct']:+.2f}%)") | |
| else: | |
| lines.append(" 数据获取中...") | |
| # 微博A股热搜 | |
| lines.append("") | |
| lines.append("🔥 【微博A股热搜】") | |
| lines.append("-" * 40) | |
| if stock_hot: | |
| for item in stock_hot[:15]: | |
| hot_num = item["hot"] | |
| if hot_num >= 1000000: | |
| hot_str = f"{hot_num/10000:.0f}万" | |
| elif hot_num >= 10000: | |
| hot_str = f"{hot_num/10000:.1f}万" | |
| else: | |
| hot_str = str(hot_num) | |
| lines.append(f" #{item['keyword']}# 🔥{hot_str} ({item['match_reason']})") | |
| else: | |
| lines.append(" 暂无A股相关热搜") | |
| # 涨停板 | |
| lines.append("") | |
| lines.append("🟢 【涨停板 TOP10】") | |
| lines.append("-" * 40) | |
| if zt_dt.get("涨停"): | |
| for item in zt_dt["涨停"]: | |
| lines.append(f" {item['name']}({item['code']}) +{item['change_pct']:.1f}% {item.get('reason', '')}") | |
| else: | |
| lines.append(" 数据获取中...") | |
| # 跌停板 | |
| lines.append("") | |
| lines.append("🔴 【跌停板 TOP10】") | |
| lines.append("-" * 40) | |
| if zt_dt.get("跌停"): | |
| for item in zt_dt["跌停"]: | |
| lines.append(f" {item['name']}({item['code']}) {item['change_pct']:.1f}%") | |
| else: | |
| lines.append(" 无跌停或数据获取中...") | |
| # 热门板块 | |
| lines.append("") | |
| lines.append("📊 【热门板块 TOP10】") | |
| lines.append("-" * 40) | |
| if sectors: | |
| for item in sectors: | |
| arrow = "🔴" if item["change_pct"] < 0 else "🟢" | |
| lines.append(f" {arrow} {item['name']}: {item['change_pct']:+.2f}% 领涨: {item['leader']}") | |
| else: | |
| lines.append(" 数据获取中...") | |
| # 关联分析 | |
| lines.append("") | |
| lines.append("🔗 【热搜 vs 行情 关联分析】") | |
| lines.append("-" * 40) | |
| if correlation["hot_stock_mentions"]: | |
| lines.append(f" 💬 热搜提及个股: {', '.join(correlation['hot_stock_mentions'][:5])}") | |
| if correlation["potential_analysis"]: | |
| for note in correlation["potential_analysis"]: | |
| lines.append(f" {note}") | |
| if not correlation["potential_analysis"] and not correlation["hot_stock_mentions"]: | |
| lines.append(" 暂无明显关联") | |
| lines.append("") | |
| lines.append("=" * 50) | |
| lines.append("📌 数据来源: 微博热搜 + AKShare (东方财富)") | |
| lines.append("⚠️ 仅供参考,不构成投资建议") | |
| return "\n".join(lines) | |
| # ============================================================ | |
| # Main | |
| # ============================================================ | |
| def main(): | |
| json_mode = "--json" in sys.argv | |
| print("🔍 正在抓取数据...\n", file=sys.stderr) | |
| # 1. 微博热搜 | |
| print(" 📱 微博热搜...", file=sys.stderr) | |
| hot_list = fetch_weibo_hot() | |
| stock_hot = filter_stock_keywords(hot_list) | |
| # 2. 大盘指数 | |
| print(" 📈 大盘指数...", file=sys.stderr) | |
| market = fetch_market_overview() | |
| # 3. 涨停/跌停 | |
| print(" 🟢 涨停/跌停...", file=sys.stderr) | |
| zt_dt = fetch_zt_dt() | |
| # 4. 热门板块 | |
| print(" 📊 热门板块...", file=sys.stderr) | |
| sectors = fetch_hot_sectors() | |
| # 5. 关联分析 | |
| print(" 🔗 关联分析...", file=sys.stderr) | |
| correlation = analyze_correlation(stock_hot, zt_dt, sectors) | |
| # 6. 输出 | |
| if json_mode: | |
| result = { | |
| "timestamp": datetime.now().isoformat(), | |
| "weibo_hot_total": len(hot_list), | |
| "stock_hot": stock_hot, | |
| "market": market, | |
| "zt_dt": zt_dt, | |
| "sectors": sectors, | |
| "correlation": correlation, | |
| } | |
| print(json.dumps(result, ensure_ascii=False, indent=2)) | |
| else: | |
| report = generate_report(hot_list, stock_hot, market, zt_dt, sectors, correlation) | |
| print(report) | |
| if __name__ == "__main__": | |
| main() | |