import requests import pandas as pd import json from datetime import datetime import matplotlib.pyplot as plt import matplotlib import numpy as np import tkinter as tk from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体为黑体 matplotlib.rcParams['axes.unicode_minus'] = False # 解决负号显示问题 def get_fund_flow_data(): """获取资金流向数据,包括板块和股票名称""" url = "https://push2delay.eastmoney.com/api/qt/clist/get" params = { 'fid': 'f184', 'po': '1', 'pz': '50', 'pn': '1', 'np': '1', 'fltt': '2', 'invt': '2', 'fields': 'f2,f3,f12,f13,f14,f62,f184,f225,f165,f263,f109,f175,f264,f160,f100,f124,f265,f1', 'ut': 'b2884a393a59ad64002292a3e90d46a5', 'fs': 'm:0+t:6+f:!2,m:0+t:13+f:!2,m:0+t:80+f:!2,m:1+t:2+f:!2,m:1+t:23+f:!2,m:0+t:7+f:!2,m:1+t:3+f:!2', } headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Referer': 'https://data.eastmoney.com/zjlx/list.html' } try: response = requests.get(url, params=params, headers=headers) data = json.loads(response.text) if 'data' not in data or 'diff' not in data['data']: raise Exception("未能获取到数据") items = data['data']['diff'] parsed_data = [] for idx, item in enumerate(items[:50]): # 获取每个板块的股票名称 stock_names = item.get('f14', '') if isinstance(stock_names, str): stock_names = stock_names.split(';') # 假设股票名称以分号分隔 else: stock_names = [] # 如果 f62 为空或格式不正确,设置为空列表 if not stock_names: continue # 确保涨停数是有效的数字,并且为正数 limit_up_count = item.get('f165', 0) if not isinstance(limit_up_count, (int, float)) or limit_up_count < 0: limit_up_count = 0 parsed_data.append({ '板块': item.get('f100', '未知板块'), '涨停数': limit_up_count, # 获取涨停股数,确保是非负数 }) # 确保至少有一些数据 if not parsed_data: raise Exception("未能解析到有效的板块数据") return pd.DataFrame(parsed_data) except Exception as e: print(f"获取数据时发生错误: {str(e)}") return None def create_pie_chart(data): """创建涨停股数的扇形图""" # 确保所有要绘制的值都是正数 filtered_data = data[data['涨停数'] > 0].copy() # 如果没有正数值,给用户提示并返回 if filtered_data.empty: print("没有找到正数的涨停股数,无法绘制饼图") return None # 获取前15个有效的板块的涨停股数 filtered_data = filtered_data.sort_values('涨停数', ascending=False).head(15) sectors = filtered_data['板块'].tolist() pie_data = filtered_data['涨停数'].tolist() # 确保数据长度一致且非空 if not sectors or not pie_data or len(sectors) != len(pie_data): print("数据不一致或为空,无法绘制饼图") return None # 打印一下要绘制的数据,用于调试 print("要绘制的数据:") for i, (sector, value) in enumerate(zip(sectors, pie_data)): print(f"{i + 1}. {sector}: {value}") root = tk.Tk() root.title("前15板块涨停股数占比") root.geometry("800x600") root.configure(bg='#2C3E50') # 深色背景 # 创建Matplotlib图形 fig = plt.Figure(figsize=(8, 6), facecolor='#FFFFFF') ax = fig.add_subplot(111) # 设置图形背景颜色 ax.set_facecolor('#2C3E50') # 绘制扇形图 wedges, texts, autotexts = ax.pie( pie_data, labels=sectors, autopct='%1.1f%%', startangle=140, colors=plt.cm.Paired.colors, # 使用配色方案 wedgeprops={'edgecolor': 'black', 'linewidth': 0.5} # 设置扇形边框 ) # 设置标题 ax.set_title('前15板块涨停股数占比', fontsize=16, color='black', pad=20) # 设置标签样式 for text in texts: text.set_fontsize(10) text.set_color('black') for autotext in autotexts: autotext.set_fontsize(10) autotext.set_color('black') # 设置图例 ax.legend(wedges, sectors, title="板块", loc="upper left", fontsize=10, bbox_to_anchor=(1, 1)) # 将图形添加到Tkinter窗口 canvas = FigureCanvasTkAgg(fig, master=root) canvas.draw() canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) # 添加关闭按钮 close_button = tk.Button(root, text="关闭", command=root.quit, font=('SimHei', 12), bg='#C82423', fg='white', padx=10, pady=5) close_button.pack(side=tk.BOTTOM, pady=10) # 启动Tkinter主循环 root.mainloop() return root def main(): # 获取资金流向数据 print("正在获取资金流向数据...") data = get_fund_flow_data() if data is not None: # 保存数据到Excel current_date = datetime.now().strftime('%Y%m%d') output_file = f'fund_flow_ranking_{current_date}.xlsx' data.to_excel(output_file, index=False) print(f"资金流向数据已保存到: {output_file}") # 检查数据是否包含有效的涨停数 if data['涨停数'].max() <= 0: print("警告: 没有找到正的涨停数据,无法绘制饼图") else: # 创建并显示扇形图 print("正在创建扇形图...") create_pie_chart(data) else: print("获取数据失败,请检查网络连接或接口可用性。") if __name__ == "__main__": main()