aaroncxxx's picture
v1.0 首发:微博热搜 + A股行情 + 涨停跌停 + 板块热度 + 关联分析
b915cde verified
#!/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()