aishare-txt 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ 沪深300主板成分股数据获取工具
5
+
6
+ 主要功能:
7
+ - 获取沪深300成分股中的主板股票(过滤掉创业板和科创板)
8
+ - 返回包含股票代码、名称、价格、涨跌幅等信息的DataFrame
9
+ - 基于东方财富行情API,实时数据
10
+
11
+ 使用方法:
12
+ from final_stock_api import get_hs300_main_board_stocks
13
+
14
+ # 获取数据
15
+ df = get_hs300_main_board_stocks()
16
+
17
+ if df is not None:
18
+ print(f"获取到 {len(df)} 只股票")
19
+ print(df.head())
20
+ """
21
+
22
+ import requests
23
+ import pandas as pd
24
+ import json
25
+ import time
26
+ from datetime import datetime
27
+
28
+ class FinalStockAPI:
29
+ def __init__(self):
30
+ self.session = requests.Session()
31
+ self.base_url = "https://push2.eastmoney.com/api/qt/clist/get"
32
+ self.setup_headers()
33
+
34
+ def setup_headers(self):
35
+ """设置请求头"""
36
+ self.session.headers.update({
37
+ 'Accept': '*/*',
38
+ 'Accept-Language': 'zh-CN,zh;q=0.9',
39
+ 'Cache-Control': 'no-cache',
40
+ 'Connection': 'keep-alive',
41
+ 'Host': 'push2.eastmoney.com',
42
+ 'Referer': 'https://quote.eastmoney.com/',
43
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
44
+ })
45
+
46
+ def fetch_stock_data(self, market_filter="m:0 t:6,m:0 t:80,m:1 t:2,m:1 t:23", page_size=50):
47
+ """获取股票数据"""
48
+
49
+ # 构建请求参数
50
+ params = {
51
+ 'pn': '1', # 页码
52
+ 'pz': str(page_size), # 每页数量
53
+ 'po': '1', # 排序
54
+ 'np': '1', #
55
+ 'ut': 'bd1d9ddb04089700cf9c27f6f7426281', # token
56
+ 'fltt': '2', # 过滤类型
57
+ 'invt': '2', #
58
+ 'fid': 'f3', # 排序字段(涨跌幅)
59
+ 'fs': market_filter, # 市场过滤
60
+ 'fields': 'f12,f14,f2,f3,f4,f5,f6,f7,f15,f16,f17,f18,f8,f10,f9,f23,f20,f21,f13' # 字段
61
+ }
62
+
63
+ try:
64
+ # 发起请求
65
+ response = self.session.get(self.base_url, params=params, timeout=30)
66
+
67
+ if response.status_code == 200:
68
+ response_text = response.text
69
+
70
+ # 确保内容是JSON格式
71
+ if response_text.strip().startswith('{'):
72
+ try:
73
+ data = response.json()
74
+
75
+ # 检查数据结构
76
+ if 'data' in data and data['data'] and 'diff' in data['data']:
77
+ stock_list = data['data']['diff']
78
+ if stock_list:
79
+ return stock_list
80
+
81
+ except json.JSONDecodeError:
82
+ pass
83
+
84
+ except Exception:
85
+ pass
86
+
87
+ return None
88
+
89
+ def get_all_stocks(self, page_size=50):
90
+ """获取所有A股"""
91
+ return self.fetch_stock_data("m:0 t:6,m:0 t:80,m:1 t:2,m:1 t:23", page_size)
92
+
93
+ def get_hs300_stocks_all_pages(self):
94
+ """获取全部沪深300成分股(分页获取)"""
95
+ all_stocks = []
96
+ page = 1
97
+ page_size = 100 # 每页100只
98
+
99
+ while True:
100
+ # 分页获取股票数据
101
+ stocks = self.fetch_stock_data_with_page("b:BK0500", page, page_size)
102
+
103
+ if stocks:
104
+ all_stocks.extend(stocks)
105
+
106
+ # 如果获取的股票数量小于page_size,说明已到最后一页
107
+ if len(stocks) < page_size:
108
+ break
109
+
110
+ page += 1
111
+ else:
112
+ break
113
+
114
+ return all_stocks
115
+
116
+ def fetch_stock_data_with_page(self, market_filter, page, page_size):
117
+ """带分页的获取股票数据"""
118
+
119
+ # 构建请求参数
120
+ params = {
121
+ 'pn': str(page), # 页码
122
+ 'pz': str(page_size), # 每页数量
123
+ 'po': '1', # 排序
124
+ 'np': '1', #
125
+ 'ut': 'bd1d9ddb04089700cf9c27f6f7426281', # token
126
+ 'fltt': '2', # 过滤类型
127
+ 'invt': '2', #
128
+ 'fid': 'f3', # 排序字段(涨跌幅)
129
+ 'fs': market_filter, # 市场过滤
130
+ 'fields': 'f12,f14,f2,f3,f4,f5,f6,f7,f15,f16,f17,f18,f8,f10,f9,f23,f20,f21,f13' # 字段
131
+ }
132
+
133
+ try:
134
+ # 发起请求
135
+ response = self.session.get(self.base_url, params=params, timeout=30)
136
+
137
+ if response.status_code == 200:
138
+ response_text = response.text
139
+
140
+ if response_text.strip().startswith('{'):
141
+ try:
142
+ data = response.json()
143
+
144
+ # 检查数据结构
145
+ if 'data' in data and data['data'] and 'diff' in data['data']:
146
+ stock_list = data['data']['diff']
147
+ return stock_list
148
+
149
+ except json.JSONDecodeError:
150
+ pass
151
+
152
+ except Exception:
153
+ pass
154
+
155
+ return None
156
+
157
+ def get_main_board_stocks(self, page_size=50):
158
+ """获取主板股票"""
159
+ return self.fetch_stock_data("m:0 t:6,m:1 t:2,m:1 t:23", page_size)
160
+
161
+ def get_growth_stocks(self, page_size=50):
162
+ """获取创业板股票"""
163
+ return self.fetch_stock_data("m:0 t:80", page_size)
164
+
165
+ def is_main_board_stock(self, stock_code):
166
+ """判断是否为主板股票"""
167
+ if not stock_code:
168
+ return False
169
+
170
+ # 上海主板:600xxx, 601xxx, 603xxx, 605xxx
171
+ # 深圳主板:000xxx, 001xxx, 002xxx
172
+ # 创业板:300xxx(排除)
173
+ # 科创板:688xxx(排除)
174
+
175
+ if stock_code.startswith(('600', '601', '603', '605')): # 上海主板
176
+ return True
177
+ elif stock_code.startswith(('000', '001', '002')): # 深圳主板
178
+ return True
179
+ else:
180
+ return False # 创业板(300xxx)、科创板(688xxx)等
181
+
182
+ def format_dataframe(self, stock_list, filter_main_board=True):
183
+ """格式化股票数据为DataFrame"""
184
+ if not stock_list:
185
+ return None
186
+
187
+ formatted_data = []
188
+
189
+ for stock in stock_list:
190
+ try:
191
+ stock_code = stock.get('f12', '')
192
+
193
+ # 如果开启主板过滤,则只保留主板股票
194
+ if filter_main_board and not self.is_main_board_stock(stock_code):
195
+ continue
196
+
197
+ # 根据东方财富API字段映射
198
+ formatted_stock = {
199
+ '股票代码': stock_code, # f12: 股票代码
200
+ '股票名称': stock.get('f14', ''), # f14: 股票名称
201
+ '最新价': float(stock.get('f2', 0)) if stock.get('f2') else 0, # f2: 最新价
202
+ '涨跌幅(%)': float(stock.get('f3', 0)) if stock.get('f3') else 0, # f3: 涨跌幅
203
+ '涨跌额': float(stock.get('f4', 0)) if stock.get('f4') else 0, # f4: 涨跌额
204
+ '成交量(手)': int(stock.get('f5', 0)) if stock.get('f5') else 0, # f5: 成交量
205
+ '成交额': int(stock.get('f6', 0)) if stock.get('f6') else 0, # f6: 成交额
206
+ '振幅(%)': float(stock.get('f7', 0)) if stock.get('f7') else 0, # f7: 振幅
207
+ '最高价': float(stock.get('f15', 0)) if stock.get('f15') else 0, # f15: 最高价
208
+ '最低价': float(stock.get('f16', 0)) if stock.get('f16') else 0, # f16: 最低价
209
+ '今开': float(stock.get('f17', 0)) if stock.get('f17') else 0, # f17: 今开
210
+ '昨收': float(stock.get('f18', 0)) if stock.get('f18') else 0, # f18: 昨收
211
+ '换手率(%)': float(stock.get('f8', 0)) if stock.get('f8') else 0, # f8: 换手率
212
+ '量比': float(stock.get('f10', 0)) if stock.get('f10') else 0, # f10: 量比
213
+ '市盈率': float(stock.get('f9', 0)) if stock.get('f9') else 0, # f9: 市盈率
214
+ '市净率': float(stock.get('f23', 0)) if stock.get('f23') else 0, # f23: 市净率
215
+ '总市值': int(stock.get('f20', 0)) if stock.get('f20') else 0, # f20: 总市值
216
+ '流通市值': int(stock.get('f21', 0)) if stock.get('f21') else 0, # f21: 流通市值
217
+ '市场': '上交所' if stock.get('f13') == 1 else '深交所', # f13: 市场
218
+ '板块': self.get_board_type(stock_code), # 板块类型
219
+ '数据时间': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
220
+ }
221
+
222
+ formatted_data.append(formatted_stock)
223
+
224
+ except Exception:
225
+ continue
226
+
227
+ if formatted_data:
228
+ df = pd.DataFrame(formatted_data)
229
+ # 按换手率由大到小排序
230
+ df = df.sort_values('换手率(%)', ascending=False).reset_index(drop=True)
231
+ return df
232
+
233
+ return None
234
+
235
+ def get_board_type(self, stock_code):
236
+ """获取板块类型"""
237
+ if stock_code.startswith(('600', '601', '603', '605')):
238
+ return '上海主板'
239
+ elif stock_code.startswith(('000', '001', '002')):
240
+ return '深圳主板'
241
+ elif stock_code.startswith('300'):
242
+ return '创业板'
243
+ elif stock_code.startswith('688'):
244
+ return '科创板'
245
+ else:
246
+ return '其他'
247
+
248
+ def get_hs300_main_board_stocks():
249
+ """获取沪深300主板成分股数据DataFrame
250
+
251
+ Returns:
252
+ pandas.DataFrame: 沪深300主板成分股数据,包含股票代码、名称、价格等信息
253
+ None: 获取失败时返回None
254
+
255
+ 使用示例:
256
+ # 获取数据
257
+ df = get_hs300_main_board_stocks()
258
+
259
+ # 检查数据
260
+ if df is not None:
261
+ print(f"获取到 {len(df)} 只股票")
262
+ print(df.head())
263
+
264
+ # 保存到文件
265
+ df.to_csv('hs300_main_board.csv', index=False, encoding='utf-8-sig')
266
+ else:
267
+ print("获取数据失败")
268
+ """
269
+ try:
270
+ # 创建API客户端
271
+ api = FinalStockAPI()
272
+
273
+ # 获取沪深300成分股数据
274
+ stock_list = api.get_hs300_stocks_all_pages()
275
+
276
+ if stock_list:
277
+ # 格式化数据(自动过滤掉非主板股票)
278
+ df = api.format_dataframe(stock_list, filter_main_board=True)
279
+ return df
280
+
281
+ return None
282
+
283
+ except Exception:
284
+ return None
285
+
286
+ if __name__ == "__main__":
287
+ # 测试示例
288
+ df = get_hs300_main_board_stocks()
289
+
290
+ if df is not None:
291
+ print(f"成功获取 {len(df)} 只沪深300主板成分股")
292
+ print("\n板块分布:")
293
+ print(df['板块'].value_counts())
294
+
295
+ # 保存数据
296
+ timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
297
+ filename = f"沪深300主板成分股_{timestamp}.csv"
298
+ df.to_csv(filename, index=False, encoding='utf-8-sig')
299
+ print(f"\n数据已保存到: {filename}")
300
+ else:
301
+ print("获取数据失败")
302
+
303
+
304
+ # 向后兼容的别名
305
+ get_stock_list = get_hs300_main_board_stocks