aaroncxxx commited on
Commit
ca2bd53
·
verified ·
1 Parent(s): b915cde

v1.1.0: 北向资金/5日趋势/关键词增强/本地快照

Browse files
Files changed (1) hide show
  1. scripts/analyzer.py +186 -504
scripts/analyzer.py CHANGED
@@ -1,504 +1,186 @@
1
- #!/usr/bin/env python3
2
- """
3
- A股微博热搜分析 v1.0
4
- - 微博热搜抓取 + A股关键词筛选
5
- - A股行情数据(大盘/涨停/跌停/板块)
6
- - 热搜 vs 行情关联分析
7
- """
8
-
9
- import json
10
- import sys
11
- import os
12
- import urllib.request
13
- import urllib.error
14
- from datetime import datetime
15
-
16
- # ============================================================
17
- # 参数解析
18
- # ============================================================
19
- JSON_MODE = "--json" in sys.argv
20
- BRIEF_MODE = "--brief" in sys.argv
21
- NO_WEIBO = "--no-weibo" in sys.argv
22
- NO_MARKET = "--no-market" in sys.argv
23
-
24
- # ============================================================
25
- # 1. 微博热搜抓取
26
- # ============================================================
27
- def fetch_weibo_hot(retries=2):
28
- """获取微博实时热搜带重试"""
29
- url = "https://weibo.com/ajax/side/hotSearch"
30
- headers = {
31
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
32
- "Accept": "application/json, text/plain, */*",
33
- "Referer": "https://weibo.com",
34
- "X-Requested-With": "XMLHttpRequest",
35
- }
36
-
37
- for attempt in range(retries + 1):
38
- try:
39
- req = urllib.request.Request(url, headers=headers)
40
- with urllib.request.urlopen(req, timeout=10) as resp:
41
- data = json.loads(resp.read().decode("utf-8"))
42
-
43
- hot_list = data.get("data", {}).get("realtime", [])
44
- results = []
45
- for item in hot_list[:50]:
46
- results.append({
47
- "rank": item.get("rank", 0),
48
- "keyword": item.get("word", ""),
49
- "hot": item.get("num", 0),
50
- "category": item.get("category", ""),
51
- "label": item.get("label_name", ""),
52
- "icon_desc": item.get("icon_desc", ""),
53
- })
54
- return results
55
- except Exception as e:
56
- if attempt < retries:
57
- import time
58
- time.sleep(1)
59
- continue
60
- log(f"⚠️ 微博热搜获取失败: {e}")
61
- return []
62
-
63
-
64
- def filter_stock_keywords(hot_list):
65
- """筛选A股相关关键词"""
66
- # 精确匹配关键词
67
- exact_keywords = [
68
- "A股", "大A", "股市", "股票", "涨停", "跌停", "牛市", "熊市",
69
- "基金", "证券", "券商", "上证", "深证", "创业板", "科创板",
70
- "涨停板", "跌停板", "打板", "龙头", "妖股",
71
- "利好", "利空", "暴跌", "暴涨", "反弹", "回调",
72
- "北向资金", "主力", "游资", "散户",
73
- ]
74
-
75
- # 模糊匹配关键词
76
- fuzzy_chars = ["股", "涨", "跌", "板", "牛市", "熊市", "基金", "证券", "金融"]
77
-
78
- stock_related = []
79
- for item in hot_list:
80
- keyword = item["keyword"]
81
-
82
- # 精确匹配
83
- matched = False
84
- for kw in exact_keywords:
85
- if kw in keyword:
86
- item["match_reason"] = f"包含「{kw}」"
87
- stock_related.append(item)
88
- matched = True
89
- break
90
-
91
- # 模糊匹配
92
- if not matched:
93
- for ch in fuzzy_chars:
94
- if ch in keyword and len(keyword) <= 15:
95
- item["match_reason"] = "模糊匹配"
96
- stock_related.append(item)
97
- break
98
-
99
- return stock_related
100
-
101
-
102
- # ============================================================
103
- # 2. A股行情数据 (AKShare)
104
- # ============================================================
105
- def fetch_market_overview():
106
- """获取大盘指"""
107
- try:
108
- import akshare as ak
109
- import warnings
110
- warnings.filterwarnings("ignore")
111
-
112
- indices = [
113
- ("sh000001", "上证指数"),
114
- ("sz399001", "深证成指"),
115
- ("sz399006", "创业板指"),
116
- ]
117
-
118
- results = []
119
- for symbol, name in indices:
120
- try:
121
- df = ak.stock_zh_index_daily(symbol=symbol)
122
- if df is not None and len(df) >= 2:
123
- last = df.iloc[-1]
124
- prev = df.iloc[-2]
125
- close = float(last["close"])
126
- prev_close = float(prev["close"])
127
- change_pct = (close - prev_close) / prev_close * 100
128
- results.append({
129
- "name": name,
130
- "close": round(close, 2),
131
- "change_pct": round(change_pct, 2),
132
- })
133
- except Exception:
134
- continue
135
-
136
- return results
137
- except Exception as e:
138
- log(f"⚠️ 大盘数据获取失败: {e}")
139
- return []
140
-
141
-
142
- def fetch_zt_dt():
143
- """获取涨停/跌停数据"""
144
- today = datetime.now().strftime("%Y%m%d")
145
- result = {"涨停": [], "跌停": []}
146
-
147
- try:
148
- import akshare as ak
149
- import warnings
150
- warnings.filterwarnings("ignore")
151
-
152
- # 涨停板
153
- try:
154
- zt_df = ak.stock_zt_pool_em(date=today)
155
- if zt_df is not None and not zt_df.empty:
156
- for _, row in zt_df.head(15).iterrows():
157
- result["涨停"].append({
158
- "code": str(row.get("代码", "")),
159
- "name": str(row.get("名称", "")),
160
- "change_pct": float(row.get("涨跌幅", 0)),
161
- "reason": str(row.get("涨停原因", "")),
162
- "turnover": str(row.get("换手率", "")),
163
- })
164
- except Exception:
165
- pass
166
-
167
- # 跌停板
168
- try:
169
- dt_df = ak.stock_zt_pool_dtgc_em(date=today)
170
- if dt_df is not None and not dt_df.empty:
171
- for _, row in dt_df.head(15).iterrows():
172
- result["跌停"].append({
173
- "code": str(row.get("代码", "")),
174
- "name": str(row.get("名称", "")),
175
- "change_pct": float(row.get("涨跌幅", 0)),
176
- })
177
- except Exception:
178
- pass
179
-
180
- except Exception as e:
181
- log(f"⚠️ 涨停/跌停数据获失败: {e}")
182
-
183
- return result
184
-
185
-
186
- def fetch_hot_sectors():
187
- """获取热门板块"""
188
- try:
189
- import akshare as ak
190
- import warnings
191
- warnings.filterwarnings("ignore")
192
-
193
- df = ak.stock_board_industry_name_em()
194
- if df is not None and not df.empty:
195
- sectors = []
196
- for _, row in df.head(15).iterrows():
197
- sectors.append({
198
- "name": str(row.get("板块名称", "")),
199
- "change_pct": float(row.get("涨跌幅", 0)),
200
- "leader": str(row.get("领涨股票", "")),
201
- "leader_change": float(row.get("领涨股票-涨跌幅", 0)) if "领涨股票-涨跌幅" in row else 0,
202
- "up_count": int(row.get("上涨家数", 0)) if "上涨家数" in row else 0,
203
- "down_count": int(row.get("下跌家数", 0)) if "下跌家数" in row else 0,
204
- })
205
- return sectors
206
- return []
207
- except Exception as e:
208
- log(f"⚠️ 板块数据获取失败: {e}")
209
- return []
210
-
211
-
212
- def fetch_top_stocks():
213
- """获取涨幅/跌幅前10"""
214
- try:
215
- import akshare as ak
216
- import warnings
217
- warnings.filterwarnings("ignore")
218
-
219
- df = ak.stock_zh_a_spot_em()
220
- if df is not None and not df.empty:
221
- # 涨幅前10
222
- top_up = df.nlargest(10, "涨跌幅")[["代码", "名称", "涨跌幅", "最新价", "成交额"]].to_dict("records")
223
- # 跌幅前10
224
- top_down = df.nsmallest(10, "涨跌幅")[["代码", "名称", "涨跌幅", "最新价", "成交额"]].to_dict("records")
225
- # 成交额前10
226
- top_volume = df.nlargest(10, "成交额")[["代码", "名称", "涨跌幅", "最新价", "成交额"]].to_dict("records")
227
-
228
- return {
229
- "涨幅榜": [{"code": str(r["代码"]), "name": str(r["名称"]), "change_pct": float(r["涨跌幅"]), "price": float(r["最新价"]) if r["最新价"] else 0, "volume": float(r["成交额"]) if r["成交额"] else 0} for r in top_up],
230
- "跌幅榜": [{"code": str(r["代码"]), "name": str(r["名称"]), "change_pct": float(r["涨跌幅"]), "price": float(r["最新价"]) if r["最新价"] else 0, "volume": float(r["成交额"]) if r["成交额"] else 0} for r in top_down],
231
- "成交榜": [{"code": str(r["代码"]), "name": str(r["名称"]), "change_pct": float(r["涨跌幅"]), "price": float(r["最新价"]) if r["最新价"] else 0, "volume": float(r["成交额"]) if r["成交额"] else 0} for r in top_volume],
232
- }
233
- return {}
234
- except Exception as e:
235
- log(f"⚠️ 个股排行获取失败: {e}")
236
- return {}
237
-
238
-
239
- # ============================================================
240
- # 3. 关联分析
241
- # ============================================================
242
- def analyze_correlation(stock_hot, zt_dt, sectors):
243
- """分析热搜与行情的关联"""
244
- analysis = {
245
- "hot_stock_mentions": [],
246
- "hot_and_zt": [],
247
- "hot_sectors": [],
248
- "insights": [],
249
- }
250
-
251
- # 提取热搜中的个股名
252
- stock_names = []
253
- for item in stock_hot:
254
- keyword = item["keyword"]
255
- # 去掉 # 号和通用词
256
- clean = keyword.replace("#", "")
257
- if 2 <= len(clean) <= 8:
258
- stock_names.append(clean)
259
-
260
- analysis["hot_stock_mentions"] = stock_names[:10]
261
-
262
- # 与涨停板交叉
263
- zt_names = [item["name"] for item in zt_dt.get("涨停", [])]
264
- zt_reasons = {item["name"]: item.get("reason", "") for item in zt_dt.get("涨停", [])}
265
- mentioned_and_zt = [name for name in stock_names if name in zt_names]
266
-
267
- if mentioned_and_zt:
268
- analysis["hot_and_zt"] = mentioned_and_zt
269
- analysis["insights"].append(
270
- f"🔥 同时出现在微博热搜和涨停板: {', '.join(mentioned_and_zt)}"
271
- )
272
-
273
- # 热搜板块
274
- sector_keywords = []
275
- for item in stock_hot:
276
- kw = item["keyword"]
277
- if any(w in kw for w in ["板块", "概念", "题材"]):
278
- sector_keywords.append(kw)
279
-
280
- if sector_keywords:
281
- analysis["hot_sectors"] = sector_keywords
282
- analysis["insights"].append(
283
- f"📊 热搜板块关键词: {', '.join(sector_keywords[:5])}"
284
- )
285
-
286
- # 涨停原因分析
287
- if zt_dt.get("涨停"):
288
- reasons = {}
289
- for item in zt_dt["涨停"]:
290
- reason = item.get("reason", "").strip()
291
- if reason:
292
- reasons[reason] = reasons.get(reason, 0) + 1
293
- if reasons:
294
- top_reasons = sorted(reasons.items(), key=lambda x: -x[1])[:3]
295
- for reason, count in top_reasons:
296
- analysis["insights"].append(f"📈 涨停原因「{reason}」: {count} 只")
297
-
298
- return analysis
299
-
300
-
301
- # ============================================================
302
- # 4. 报告生成
303
- # ============================================================
304
- def format_hot(num):
305
- """格式化热度数字"""
306
- if num >= 1000000:
307
- return f"{num/10000:.0f}万"
308
- elif num >= 10000:
309
- return f"{num/10000:.1f}万"
310
- return str(num)
311
-
312
-
313
- def log(msg):
314
- """日志输出"""
315
- if not JSON_MODE:
316
- print(msg, file=sys.stderr)
317
-
318
-
319
- def generate_report(data):
320
- """生成完整报告"""
321
- now = datetime.now().strftime("%Y-%m-%d %H:%M")
322
-
323
- lines = []
324
- lines.append(f"📊 A股微博热搜分析报告")
325
- lines.append(f"⏰ {now}")
326
- lines.append("=" * 50)
327
-
328
- # 大盘
329
- market = data.get("market", [])
330
- lines.append("")
331
- lines.append("📈 【大盘概览】")
332
- lines.append("-" * 40)
333
- if market:
334
- for m in market:
335
- arrow = "🔴" if m["change_pct"] < 0 else "🟢"
336
- lines.append(f" {arrow} {m['name']}: {m['close']} ({m['change_pct']:+.2f}%)")
337
- else:
338
- lines.append(" 数据获取中...")
339
-
340
- # 微博热搜
341
- stock_hot = data.get("stock_hot", [])
342
- lines.append("")
343
- lines.append(f"🔥 【微博A股热搜】 ({len(stock_hot)} 条)")
344
- lines.append("-" * 40)
345
- if stock_hot:
346
- for item in stock_hot[:15]:
347
- lines.append(f" #{item['keyword']}# 🔥{format_hot(item['hot'])} ({item['match_reason']})")
348
- else:
349
- lines.append(" 暂无A股相关热搜")
350
-
351
- if BRIEF_MODE:
352
- # 精简模式只显示涨停
353
- lines.append("")
354
- lines.append("🟢 【涨停板】")
355
- lines.append("-" * 40)
356
- zt = data.get("zt_dt", {}).get("涨停", [])
357
- for item in zt[:10]:
358
- lines.append(f" {item['name']}({item['code']}) +{item['change_pct']:.1f}% {item.get('reason', '')}")
359
-
360
- lines.append("")
361
- lines.append("=" * 50)
362
- lines.append("📌 数据来源: 微博热搜 + AKShare")
363
- return "\n".join(lines)
364
-
365
- # 涨停
366
- zt = data.get("zt_dt", {}).get("涨停", [])
367
- lines.append("")
368
- lines.append(f"🟢 【涨停板 TOP{min(15, len(zt))}】")
369
- lines.append("-" * 40)
370
- if zt:
371
- for item in zt[:15]:
372
- lines.append(f" {item['name']}({item['code']}) +{item['change_pct']:.1f}% {item.get('reason', '')}")
373
- else:
374
- lines.append(" 无涨停或数据获取中...")
375
-
376
- # 跌停
377
- dt = data.get("zt_dt", {}).get("跌停", [])
378
- lines.append("")
379
- lines.append(f"🔴 【跌停板 TOP{min(15, len(dt))}】")
380
- lines.append("-" * 40)
381
- if dt:
382
- for item in dt[:15]:
383
- lines.append(f" {item['name']}({item['code']}) {item['change_pct']:.1f}%")
384
- else:
385
- lines.append(" 无跌停或数据获取中...")
386
-
387
- # 热门板块
388
- sectors = data.get("sectors", [])
389
- lines.append("")
390
- lines.append(f"📊 【热门板块 TOP{min(10, len(sectors))}】")
391
- lines.append("-" * 40)
392
- if sectors:
393
- for item in sectors[:10]:
394
- arrow = "🔴" if item["change_pct"] < 0 else "🟢"
395
- lines.append(f" {arrow} {item['name']}: {item['change_pct']:+.2f}% 领涨: {item['leader']}")
396
- else:
397
- lines.append(" 数据获取中...")
398
-
399
- # 个股排行
400
- stocks = data.get("stocks", {})
401
- if stocks.get("涨幅榜"):
402
- lines.append("")
403
- lines.append("📈 【今日涨幅榜 TOP5】")
404
- lines.append("-" * 40)
405
- for item in stocks["涨幅榜"][:5]:
406
- lines.append(f" 🟢 {item['name']}({item['code']}) +{item['change_pct']:.1f}% ¥{item['price']}")
407
-
408
- if stocks.get("成交榜"):
409
- lines.append("")
410
- lines.append("💰 【今日成交额 TOP5】")
411
- lines.append("-" * 40)
412
- for item in stocks["成交榜"][:5]:
413
- vol_str = f"{item['volume']/100000000:.1f}亿" if item['volume'] >= 100000000 else f"{item['volume']/10000:.0f}万"
414
- lines.append(f" 💰 {item['name']}({item['code']}) {vol_str} {item['change_pct']:+.1f}%")
415
-
416
- # 关联分析
417
- corr = data.get("correlation", {})
418
- lines.append("")
419
- lines.append("🔗 【热搜 vs 行情 关联分析】")
420
- lines.append("-" * 40)
421
-
422
- if corr.get("hot_stock_mentions"):
423
- lines.append(f" 💬 热搜提及个股: {', '.join(corr['hot_stock_mentions'][:5])}")
424
-
425
- if corr.get("hot_and_zt"):
426
- lines.append(f" 🔥 热搜+涨停双重热度: {', '.join(corr['hot_and_zt'])}")
427
-
428
- if corr.get("hot_sectors"):
429
- lines.append(f" 📊 热搜板块: {', '.join(corr['hot_sectors'][:3])}")
430
-
431
- if corr.get("insights"):
432
- for note in corr["insights"]:
433
- lines.append(f" {note}")
434
-
435
- if not corr.get("insights") and not corr.get("hot_stock_mentions"):
436
- lines.append(" 暂无明显关联")
437
-
438
- lines.append("")
439
- lines.append("=" * 50)
440
- lines.append("📌 数据来源: 微博热搜 + AKShare (东方财富)")
441
- lines.append("⚠️ 仅供参考,不构成投资建议")
442
-
443
- return "\n".join(lines)
444
-
445
-
446
- # ============================================================
447
- # Main
448
- # ============================================================
449
- def main():
450
- log("🔍 正在抓取数据...\n")
451
-
452
- data = {}
453
-
454
- # 1. 微博热搜
455
- if not NO_WEIBO:
456
- log(" 📱 微博热搜...")
457
- hot_list = fetch_weibo_hot()
458
- data["weibo_hot_total"] = len(hot_list)
459
- data["stock_hot"] = filter_stock_keywords(hot_list)
460
- else:
461
- data["stock_hot"] = []
462
-
463
- # 2. 大盘指数
464
- if not NO_MARKET:
465
- log(" 📈 大盘指数...")
466
- data["market"] = fetch_market_overview()
467
- else:
468
- data["market"] = []
469
-
470
- # 3. 涨停/跌停
471
- if not NO_MARKET:
472
- log(" 🟢 涨停/跌停...")
473
- data["zt_dt"] = fetch_zt_dt()
474
- else:
475
- data["zt_dt"] = {"涨停": [], "跌停": []}
476
-
477
- # 4. 热门板块
478
- if not NO_MARKET and not BRIEF_MODE:
479
- log(" 📊 热门板块...")
480
- data["sectors"] = fetch_hot_sectors()
481
- else:
482
- data["sectors"] = []
483
-
484
- # 5. 个股排行
485
- if not NO_MARKET and not BRIEF_MODE:
486
- log(" 📈 个股排行...")
487
- data["stocks"] = fetch_top_stocks()
488
- else:
489
- data["stocks"] = {}
490
-
491
- # 6. 关联分析
492
- log(" 🔗 关联分析...")
493
- data["correlation"] = analyze_correlation(data["stock_hot"], data["zt_dt"], data["sectors"])
494
-
495
- # 7. 输出
496
- if JSON_MODE:
497
- data["timestamp"] = datetime.now().isoformat()
498
- print(json.dumps(data, ensure_ascii=False, indent=2))
499
- else:
500
- print(generate_report(data))
501
-
502
-
503
- if __name__ == "__main__":
504
- main()
 
1
+ ---
2
+ name: CNY RMB A股 China A shares Stock
3
+ version: 1.1.0
4
+ description: >
5
+ CNY RMB A股热搜分析 - China A Shares Stock Skill
6
+ 微博热搜 + A股行情 + 关联分析,一站式掌握市场热点。
7
+ 关键词:A股, 大A, A-shares, China A, Onshore, 涨停, 跌停, 热搜
8
+ applyTo: "**"
9
+ ---
10
+
11
+ # CNY RMB A股热搜分析
12
+ # China A Shares Stock Skill
13
+
14
+ 微博热搜 + A股行情 + 关联分析,一站式掌握市场热点。
15
+
16
+ > **关于作者** — 米粉,A股老韭菜,美股老韭菜,期货老韭菜,币圈老韭菜,被割多了,现在只看不玩,用MIMO做个Skill大家娱乐围观A股行情,好用记得回来点星星。⭐
17
+ >
18
+ > Mi Fan 🍚 | Rekt veteran: A-shares, US stocks, futures, crypto 📉 | Now just watching 👀 | Built with MIMO for fun | Star if you like it ⭐
19
+ >
20
+ > **功能清单:**
21
+ > - 微博实时热搜抓取 + A股关键词筛选(v1.1 增强)
22
+ > - 大盘指数(上证/深证/创业板)
23
+ > - ✅ 涨停板 / 跌停板 TOP 列表
24
+ > - ✅ 热门板块排行
25
+ > - 热搜 vs 行情关联分析
26
+ > - ✅ 🆕 北向资金实时数据(沪股通/深股通)
27
+ > - ✅ 🆕 大盘5日趋势 + 迷你趋势图
28
+ > - ✅ 🆕 行业/板块关键词库增强50+板块
29
+ > - ✅ 🆕 本地快照缓存 + 历史数据对比
30
+ > - ✅ `--json` 结构化输出
31
+ > - `--brief` 精简模式(仅热搜 + 涨停)
32
+ > - `--trend` 趋势模式(含大盘5日走势)
33
+
34
+ ## When to Use
35
+
36
+ | Situation | Use this skill? |
37
+ |---|---|
38
+ | 用户说"A股分析" / "股市热搜" / "今天行情" | ✅ Yes |
39
+ | 用户问"今天有什么热门股票" | ✅ Yes |
40
+ | 用户想看微博上大家在讨论什么股票 | Yes |
41
+ | 盘后复盘 / 盘中监控 | ✅ Yes |
42
+ | 用户问"北向资金今天流入多少" | ✅ Yes |
43
+ | 用户问"大盘最近走势怎么样" | ✅ Yes |
44
+
45
+ ## Usage
46
+
47
+ ```bash
48
+ python3 "{baseDir}/scripts/analyzer.py" [options]
49
+ ```
50
+
51
+ ### Options
52
+
53
+ | Flag | Description |
54
+ |------|-------------|
55
+ | `--json` | JSON 格式输出 |
56
+ | `--brief` | 精简模式:仅热搜 + 涨停 |
57
+ | `--trend` | 趋势模式:含大盘5日走势 |
58
+ | `--no-weibo` | 跳过微博数据(只看行情) |
59
+ | `--no-market` | 跳过行情数据(只看热搜) |
60
+
61
+ ### Examples
62
+
63
+ ```bash
64
+ # 完整分析
65
+ python3 "{baseDir}/scripts/analyzer.py"
66
+
67
+ # 精简模式
68
+ python3 "{baseDir}/scripts/analyzer.py" --brief
69
+
70
+ # 趋势模式(含大盘5日走势)
71
+ python3 "{baseDir}/scripts/analyzer.py" --trend
72
+
73
+ # JSON 输出
74
+ python3 "{baseDir}/scripts/analyzer.py" --json
75
+
76
+ # 只看行情
77
+ python3 "{baseDir}/scripts/analyzer.py" --no-weibo
78
+
79
+ # 只看热搜
80
+ python3 "{baseDir}/scripts/analyzer.py" --no-market
81
+
82
+ # 趋势 +
83
+ python3 "{baseDir}/scripts/analyzer.py" --trend --brief
84
+ ```
85
+
86
+ ## v1.1 新增内容
87
+
88
+ ### 🌊 北向资金
89
+ - 沪股通/深股通净买入数据
90
+ - 实时净流入/流出金额
91
+ - 自动格式化为亿/万亿
92
+
93
+ ### 📉 大盘5日趋势
94
+ - `--trend` 开启趋势模式
95
+ - 迷你趋势图可视化
96
+ - 5日累计涨跌幅
97
+
98
+ ### 🔍 关键词匹配增强
99
+ - 新增 50+ 行业/板块关键词
100
+ - 覆盖科技、新能源、消费、金融、制造等领域
101
+ - 板块级别精确匹配,减少模糊匹配
102
+
103
+ ### 📅 本地快照
104
+ - 自动保存每日数据到 `.cache/`
105
+ - 报告底部显示最近5天数据对比
106
+ - 涨停/跌停家变化一目了然
107
+
108
+ ## 输出格式
109
+
110
+ ```
111
+ 📊 A股微博热搜分析报告 v1.1
112
+ 2026-05-01 09:30
113
+ ==================================================
114
+
115
+ 📈 【大盘概览】
116
+ ----------------------------------------
117
+ 🟢 上证指数: 3288.41 (+0.52%)
118
+ 🔴 深证成指: 10245.67 (-0.09%)
119
+ 🔴 创业板指: 2045.12 (-0.27%)
120
+
121
+ 🌊 【北向资金】
122
+ ----------------------------------------
123
+ 🟢 净流入: 45.23亿
124
+ 沪股通净买入: 28.10亿
125
+ 深股通净买入: 17.13亿
126
+
127
+ 📉 【近5日趋势】
128
+ ----------------------------------------
129
+ 📈 上证指数: +2.15% (5日)
130
+ ▓▓▓▓▓▓░░ ▓▓▓▓▓░░░ ▓▓▓▓▓▓░░ ▓▓▓▓▓▓▓░ ▓▓▓▓▓▓▓░
131
+ 3250.12 3265.44 → 3278.90 → 3285.33 → 3288.41
132
+
133
+ 🔥 【微博A股热搜】
134
+ ----------------------------------------
135
+ #寒武纪涨停# 🔥17.5万 (板块「AI」)
136
+ #A股牛市来了# 🔥12.3万 (包含「A股」「牛市」)
137
+
138
+ 🟢 【涨停板 TOP10】
139
+ ----------------------------------------
140
+ 寒武纪(688256) +20.0% AI芯片
141
+ ...
142
+
143
+ 🔗 【热搜 vs 行情 关联分析】
144
+ ----------------------------------------
145
+ 💬 热搜提及个股: 寒武纪, 中科曙光
146
+ 🔥 热搜+涨停双重热度: 寒武纪
147
+ 📊 涨停原因「AI芯片」: 3 只
148
+
149
+ 📅 【历史数据对比】
150
+ ----------------------------------------
151
+ 📌 2026-05-01: 涨停42家 / 跌停5家 / 板块15个 北向: 45.23亿
152
+ 📌 2026-04-30: 涨停38家 / 跌停8家 / 块14个 北向: -12.50亿
153
+ 📌 2026-04-29: 涨停45家 / 跌停3家 / 板块15个 北向: 32.80亿
154
+ ```
155
+
156
+ ## 数据源
157
+
158
+ | | 说明 | 需要 API Key |
159
+ |----|------|-------------|
160
+ | 微博热搜 | 公开 API | ❌ 不需要 |
161
+ | AKShare (东方财富) | A股行情 + 北向资金 | ❌ 不需要 |
162
+
163
+ ## 依赖
164
+
165
+ - Python 3.8+
166
+ - akshare (`pip3 install akshare`)
167
+
168
+ ## 版本历史
169
+
170
+ ### v1.1.0 (2026-05-01)
171
+
172
+ - 🌊 新增北向资金数据(沪股通/深股通净买入)
173
+ - 📉 新增 `--trend` 大盘5日趋势 + 迷你趋势图
174
+ - 🔍 关键词匹配增强:50+行业/板块关键词库
175
+ - 📅 本地快照缓存 + 历史数据对比
176
+ - 🔧 修复关键词模糊匹配过于宽泛的问题
177
+ - 📝 报告标题标注版本号
178
+
179
+ ### v1.0.0 (2026-05-01)
180
+
181
+ - 🚀 首发:微博热搜抓+ A股行情 + 关联分析
182
+ - 📈 大盘指数:上证/深证/创业板
183
+ - 🟢 涨停板/跌停板 TOP 列表
184
+ - 📊 热门板块排行
185
+ - 🔗 热搜 vs 行情关联分析
186
+ - 📱 支持 `--json` / `--brief` / `--no-weibo` / `--no-market`