股票代码处理与排序
创建于:2024年12月9日
创建于:2024年12月9日
import pandas as pd
import os
import re
from io import StringIO
def determine_suffix(stock_code):
"""
根据股票代码确定后缀。
以'6'开头的代码添加'.SH',其他的添加'.SZ'。
"""
if stock_code.startswith('6'):
return '.SH'
else:
return '.SZ'
def process_stock_codes(input_codes):
"""
处理输入的股票代码,确保它们具有正确的后缀。
"""
processed_codes = []
for code in input_codes:
# 去除空白、换行和逗号,并转换为大写
code = code.strip().upper().replace(',', '').replace('\n', '').replace('\r', '')
if not code:
continue # 跳过空字符串
if '.' in code:
# 确保后缀为.SH或.SZ
parts = code.split('.')
if len(parts) != 2 or parts[1] not in ['SH', 'SZ']:
print(f"股票代码 {code} 的后缀无效。跳过。")
continue
processed_codes.append(code)
else:
suffix = determine_suffix(code)
full_code = f"{code}{suffix}"
processed_codes.append(full_code)
return processed_codes
def main():
# 步骤1:读取输入CSV文件(请根据实际路径修改)
input_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\openai-东方 - 涨停池20231214.csv"
textif not os.path.exists(input_csv_path): print(f"未找到输入CSV文件:{input_csv_path}") return try: with open(input_csv_path, 'r', encoding='gbk') as f: lines = f.readlines() # 过滤掉以“日期:”开头的行和空行 data_lines = [] header_set = False # 使用逗号分隔符匹配表头行 header_line_pattern = re.compile(r'^日期,证券代码') for line in lines: if line.startswith('日期:'): # 跳过以"日期:"开头的注释行 continue if line.strip() == '': # 跳过空行 continue if header_line_pattern.match(line): # 如果匹配到表头行且还未设置表头,则保留 if not header_set: data_lines.append(line) header_set = True else: # 已有表头则跳过后面的表头行 continue else: data_lines.append(line) if not header_set: print("未找到有效的表头信息。请检查CSV文件格式。") print("请确保CSV文件中包含类似 '日期,证券代码,...' 的表头行。") # 调试信息:打印前10行过滤后的数据 print("CSV文件的前10行(去除注释和空行):") print('\n'.join(data_lines[:10])) return # 将过滤后的数据行合并为一个字符串 data_str = ''.join(data_lines) # 使用StringIO读取过滤后的数据,并使用逗号作为分隔符 df = pd.read_csv(StringIO(data_str), sep=',', encoding='gbk', dayfirst=True) # 清理列名:去除前后空格并转换为大写 df.columns = df.columns.str.strip().str.upper() # 检查是否存在“证券代码”列 if '证券代码' not in df.columns: print("CSV文件中不包含 '证券代码' 列。请检查列名是否正确。") print("当前列名:", df.columns.tolist()) return # 确保“日期”列为日期类型 df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') # 检查是否有未解析的日期 if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") # 确保“涨停基因”列为数值类型,处理非数值数据 df['涨停基因'] = pd.to_numeric(df['涨停基因'], errors='coerce') # 调试打印数据预览 print("清理后的列名:", df.columns.tolist()) print("数据预览(前5行):") print(df.head()) except Exception as e: print(f"读取输入CSV文件时出错:{e}") return # 步骤2:获取用户输入的股票代码(支持多行输入) print("\n请输入一个或多个股票代码,使用逗号、空格或换行符分隔。") print("输入完成后请按回车换行,再按一次回车结束输入。") print("示例:") print(" - 单行:603278.SH 或 603278,300220,002086.SZ") print(" - 多行:可多行输入代码,每行一个或多个代码,完成后输入空行结束。") # 读取多行输入,直到用户输入空行 input_lines = [] while True: try: line = input() if line.strip() == '': break input_lines.append(line) except EOFError: break # 将多行输入合并为一个字符串 user_input = ' '.join(input_lines) # 使用正则表达式分割输入,支持逗号、空格和换行符 input_codes = re.split(r'[,\s]+', user_input) # 处理股票代码,确保格式正确 stock_codes = process_stock_codes(input_codes) # 调试信息:打印拆分后的代码列表和处理后的股票代码列表 print("\n拆分后的代码列表:", input_codes) print("处理后的股票代码列表:", stock_codes) if not stock_codes: print("未输入有效的股票代码。退出。") return print(f"\n处理后的股票代码:{stock_codes}") # 确保“证券代码”列为字符串类型并转换为大写 df['证券代码'] = df['证券代码'].astype(str).str.upper() # 步骤3:根据股票代码过滤数据 filtered_data = df[df['证券代码'].isin(stock_codes)].copy() if filtered_data.empty: print("未找到输入股票代码的相关数据。") return # 按证券代码和日期排序 filtered_data = filtered_data.sort_values(by=['证券代码', '日期']) # 步骤4:添加前交易日涨停基因、当日交易日涨停基因和涨停基因差 filtered_data['前交易日涨停基因'] = filtered_data.groupby('证券代码')['涨停基因'].shift(1) filtered_data['当日交易日涨停基因'] = filtered_data['涨停基因'] filtered_data['涨停基因差'] = filtered_data['当日交易日涨停基因'] - filtered_data['前交易日涨停基因'] # 填充NaN值(例如,第一条记录的前交易日涨停基因) filtered_data['前交易日涨停基因'].fillna(0, inplace=True) filtered_data['涨停基因差'].fillna(0, inplace=True) # 确保所有新列为数值类型 filtered_data['前交易日涨停基因'] = pd.to_numeric(filtered_data['前交易日涨停基因'], errors='coerce').fillna(0) filtered_data['当日交易日涨停基因'] = pd.to_numeric(filtered_data['当日交易日涨停基因'], errors='coerce').fillna(0) filtered_data['涨停基因差'] = pd.to_numeric(filtered_data['涨停基因差'], errors='coerce').fillna(0) # Reorder columns as per user requirement desired_columns = [ '日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入', '前交易日涨停基因', '当日交易日涨停基因', '涨停基因差' ] # 检查是否存在所有需要的列 missing_columns = [col for col in desired_columns if col not in filtered_data.columns] if missing_columns: print(f"警告:缺少列 {missing_columns},无法添加至输出文件中。") # 为缺失的列添加NaN for col in missing_columns: filtered_data[col] = pd.NA # 选择需要的列 output_data = filtered_data[desired_columns] # 步骤5:将数据输出到新的CSV文件(请根据实际路径修改) output_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv" try: # 按日期排序(从最早到最新) output_data = output_data.sort_values(by='日期') # 将“日期”列转换为字符串格式(如 'dd/mm/yyyy') output_data['日期'] = output_data['日期'].dt.strftime('%d/%m/%Y') # 保存到CSV文件 output_data.to_csv(output_csv_path, index=False, encoding='gbk') print(f"\n数据已成功写入:{output_csv_path}") except Exception as e: print(f"写入输出CSV文件时出错:{e}")
if name == "main":
main() 输出数据如下
日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差
12/6/2024 002031.SZ 巨轮智能 2.44 9.90990991 专用设备 65.75 今日首板 9:40:15 25425900 62039196 3.4382 80873602 #VALUE! 65.75 #VALUE!
13/12/2023 002031.SZ 巨轮智能 4.27 10.05154639 专用设备 66.75 今日首板 13:48:33 27951100 119351197 22.1947 574851033 65.75 66.75 1
14/12/2022 002031.SZ 巨轮智能 2.99 9.926470588 专用设备 68.75 今日首板 10:09:21 25784207 77094778.93 18.4115 353075358 66.75 68.75 2
18/10/2024 002031.SZ 巨轮智能 3.15 10.13986014 专用设备 68.75 今日首板 9:50:21 25455622 80185209.3 10.4286 234069375 68.75 68.75 0
18/9/2024 002031.SZ 巨轮智能 2.59 10.21276596 专用设备 68.75 今日首板 13:22:57 11915000 30859850 14.8034 194591484 68.75 68.75 0
20/12/2022 002031.SZ 巨轮智能 3.16 10.10452962 专用设备 74.75 今日首板 10:02:12 39480447 124758212.5 15.539 232397911 68.75 74.75 6
20/6/2023 002031.SZ 巨轮智能 3.55 9.907120743 专用设备 72.5 今日首板 13:35:36 40072300 142256665 20.8294 380736355 74.75 72.5 -2.25
20/9/2022 002031.SZ 巨轮智能 3.36 10.16393443 专用设备 66.75 今日首板 10:07:24 52940600 177880416 14.2956 302947914 72.5 66.75 -5.75
5/11/2024 002031.SZ 巨轮智能 4.11 9.893048128 专用设备 77.5 2天2板 14:21:27 12438250 51121207.5 28.4857 133312624 66.75 77.5 10.75
11/11/2024 002031.SZ 巨轮智能 4.61 10.02386635 专用设备 81.75 6天3板 11:22:15 19279500 88878495 20.7727 432895681 77.5 81.75 4.25
20/11/2024 002031.SZ 巨轮智能 4.55 9.903381643 专用设备 70.5 今日首板 14:22:42 33223390 151166424.5 21.4934 374841305 81.75 70.5 -11.25
29/11/2024 002031.SZ 巨轮智能 4.68 10.11764706 专用设备 67.75 今日首板 13:16:00 31728015 148487110.2 18.7282 523932919 70.5 67.75 -2.75
4/12/2024 002031.SZ 巨轮智能 6.24 10.05291005 专用设备 72 4天4板 9:35:00 36211648 225960683.5 26.2512 31031664 67.75 72 4.25
5/12/2024 002031.SZ 巨轮智能 6.86 9.935897436 专用设备 76 5天5板 9:30:39 80788543 554209405 14.9201 2936864 72 76 4
22/10/2024 002031.SZ 巨轮智能 3.6 10.09174312 专用设备 67.5 3天2板 9:56:54 35587985 128116746 13.2064 283446012 76 67.5 -8.5
29/6/2023 002031.SZ 巨轮智能 4.07 10 专用设备 75.75 今日首板 9:25:00 103854976 422689752.3 3.9202 162166113 67.5 75.75 8.25
29/8/2023 002031.SZ 巨轮智能 3.93 10.08403361 专用设备 62.75 今日首板 13:52:18 32076170 126059348.1 17.6858 425925899 75.75 62.75 -13
3/11/2023 002031.SZ 巨轮智能 3.51 10.03134796 专用设备 61.75 今日首板 9:25:00 80407995 282232062.5 3.3805 131279882 62.75 61.75 -1
30/1/2023 002031.SZ 巨轮智能 3.64 9.96978852 专用设备 64.75 今日首板 11:03:00 17227800 62709192 15.152 272002876 61.75 64.75 3
30/11/2023 002031.SZ 巨轮智能 4.02 10.1369863 专用设备 64.75 今日首板 10:16:57 37418100 150420762 14.8877 283134910 64.75 64.75 0
30/6/2023 002031.SZ 巨轮智能 4.48 10.07371007 专用设备 79.5 4天2板 9:37:03 55013167 246458988.2 19.0317 220511752 64.75 79.5 14.75
4/1/2023 002031.SZ 巨轮智能 3.62 10.03039514 专用设备 65.5 今日首板 14:06:18 44080619 159571840.8 23.4146 261534123 79.5 65.5 -14
6/11/2023 002031.SZ 巨轮智能 3.86 9.971509972 专用设备 65.5 昨日首板 9:36:48 37889967 146255272.6 14.892 112465124 65.5 65.5 0
日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差
10/2/2023 002131.SZ 利欧股份 2.08 10.05291005 互联网服务 58.75 今日首板 13:32:30 26253097 54606441.76 6.8428 226817620 #VALUE! 58.75 #VALUE!
17/6/2024 002131.SZ 利欧股份 1.5 10.29411765 互联网服务 59.75 今日首板 14:38:33 14423048 21634572 8.2001 85836178 58.75 59.75 1
15/11/2024 002131.SZ 利欧股份 2.28 10.14492754 互联网服务 56.75 今日首板 13:00:06 51444872 117294308.2 12.5194 513713638 59.75 56.75 -3
25/11/2024 002131.SZ 利欧股份 2.98 9.963099631 互联网服务 75.25 4天2板 9:55:42 90099727 268497186.5 19.2731 7402240 56.75 75.25 18.5
27/11/2024 002131.SZ 利欧股份 3.04 10.14492754 互联网服务 77.25 6天3板 10:39:45 82608443 251129666.7 25.218 342502784 75.25 77.25 2
28/11/2024 002131.SZ 利欧股份 3.34 9.868421053 互联网服务 77.25 10天5板 10:26:15 65025656 217185691 30.0933 289698176 77.25 77.25 0
29/11/2024 002131.SZ 利欧股份 3.67 9.880239521 互联网服务 77.25 11天6板 9:25:00 279918300 1027300161 3.1345 131345890 77.25 77.25 0
3.数据排序先按股票代码 再按日期 由最早日期到最新日期来排序
您提到希望将数据按照 证券代码 和 日期 进行排序,具体是先按证券代码,再按日期由最早到最新。这是一个合理的需求,尤其是在处理多支股票的数据时,能够更清晰地观察每支股票的时间序列变化。
根据您提供的代码和输出结果,以下几点需要注意:
初始排序:
['证券代码', '日期']
进行了排序:
pythonfiltered_data = filtered_data.sort_values(by=['证券代码', '日期'])
输出前的再次排序:
['日期']
进行了排序:
pythonoutput_data = output_data.sort_values(by='日期')
['证券代码', '日期']
排序的顺序,因为它仅按日期对所有证券代码的数据进行了全局排序。日期转换:
日期
列转换为了字符串格式:
pythonoutput_data['日期'] = output_data['日期'].dt.strftime('%d/%m/%Y')
日期
转换为字符串后再进行排序,会导致日期排序基于字符串顺序,而非实际的日期顺序。#VALUE!
问题:
#VALUE!
,这通常是由于在某些单元格中存在无效或不可转换的值,可能是由于数据处理中的某些步骤未正确处理这些值。为了实现您希望的排序方式,并解决 #VALUE!
问题,建议对代码进行以下修改:
移除不必要的排序:
['日期']
进行的排序,保持初始的 ['证券代码', '日期']
排序。确保日期排序正确:
日期
转换为字符串格式之前,确保数据已经按 ['证券代码', '日期']
排序。处理 #VALUE!
问题:
涨停基因差
时,所有参与计算的值都是数值类型,并正确处理缺失值。以下是根据上述建议修改后的代码片段:
pythonimport pandas as pd import os import re from io import StringIO def determine_suffix(stock_code): """ 根据股票代码确定后缀。 以'6'开头的代码添加'.SH',其他的添加'.SZ'。 """ if stock_code.startswith('6'): return '.SH' else: return '.SZ' def process_stock_codes(input_codes): """ 处理输入的股票代码,确保它们具有正确的后缀。 """ processed_codes = [] for code in input_codes: # 去除空白、换行和逗号,并转换为大写 code = code.strip().upper().replace(',', '').replace('\n', '').replace('\r', '') if not code: continue # 跳过空字符串 if '.' in code: # 确保后缀为.SH或.SZ parts = code.split('.') if len(parts) != 2 or parts[1] not in ['SH', 'SZ']: print(f"股票代码 {code} 的后缀无效。跳过。") continue processed_codes.append(code) else: suffix = determine_suffix(code) full_code = f"{code}{suffix}" processed_codes.append(full_code) return processed_codes def main(): # 步骤1:读取输入CSV文件(请根据实际路径修改) input_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\openai-东方 - 涨停池20231214.csv" if not os.path.exists(input_csv_path): print(f"未找到输入CSV文件:{input_csv_path}") return try: with open(input_csv_path, 'r', encoding='gbk') as f: lines = f.readlines() # 过滤掉以“日期:”开头的行和空行 data_lines = [] header_set = False # 使用逗号分隔符匹配表头行 header_line_pattern = re.compile(r'^日期,证券代码') for line in lines: if line.startswith('日期:'): # 跳过以"日期:"开头的注释行 continue if line.strip() == '': # 跳过空行 continue if header_line_pattern.match(line): # 如果匹配到表头行且还未设置表头,则保留 if not header_set: data_lines.append(line) header_set = True else: # 已有表头则跳过后面的表头行 continue else: data_lines.append(line) if not header_set: print("未找到有效的表头信息。请检查CSV文件格式。") print("请确保CSV文件中包含类似 '日期,证券代码,...' 的表头行。") # 调试信息:打印前10行过滤后的数据 print("CSV文件的前10行(去除注释和空行):") print('\n'.join(data_lines[:10])) return # 将过滤后的数据行合并为一个字符串 data_str = ''.join(data_lines) # 使用StringIO读取过滤后的数据,并使用逗号作为分隔符 df = pd.read_csv(StringIO(data_str), sep=',', encoding='gbk', dayfirst=True) # 清理列名:去除前后空格并转换为大写 df.columns = df.columns.str.strip().str.upper() # 检查是否存在“证券代码”列 if '证券代码' not in df.columns: print("CSV文件中不包含 '证券代码' 列。请检查列名是否正确。") print("当前列名:", df.columns.tolist()) return # 确保“日期”列为日期类型 df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') # 检查是否有未解析的日期 if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") # 确保“涨停基因”列为数值类型,处理非数值数据 df['涨停基因'] = pd.to_numeric(df['涨停基因'], errors='coerce') # 调试打印数据预览 print("清理后的列名:", df.columns.tolist()) print("数据预览(前5行):") print(df.head()) except Exception as e: print(f"读取输入CSV文件时出错:{e}") return # 步骤2:获取用户输入的股票代码(支持多行输入) print("\n请输入一个或多个股票代码,使用逗号、空格或换行符分隔。") print("输入完成后请按回车换行,再按一次回车结束输入。") print("示例:") print(" - 单行:603278.SH 或 603278,300220,002086.SZ") print(" - 多行:可多行输入代码,每行一个或多个代码,完成后输入空行结束。") # 读取多行输入,直到用户输入空行 input_lines = [] while True: try: line = input() if line.strip() == '': break input_lines.append(line) except EOFError: break # 将多行输入合并为一个字符串 user_input = ' '.join(input_lines) # 使用正则表达式分割输入,支持逗号、空格和换行符 input_codes = re.split(r'[,\s]+', user_input) # 处理股票代码,确保格式正确 stock_codes = process_stock_codes(input_codes) # 调试信息:打印拆分后的代码列表和处理后的股票代码列表 print("\n拆分后的代码列表:", input_codes) print("处理后的股票代码列表:", stock_codes) if not stock_codes: print("未输入有效的股票代码。退出。") return print(f"\n处理后的股票代码:{stock_codes}") # 确保“证券代码”列为字符串类型并转换为大写 df['证券代码'] = df['证券代码'].astype(str).str.upper() # 步骤3:根据股票代码过滤数据 filtered_data = df[df['证券代码'].isin(stock_codes)].copy() if filtered_data.empty: print("未找到输入股票代码的相关数据。") return # 按证券代码和日期排序 filtered_data = filtered_data.sort_values(by=['证券代码', '日期']) # 步骤4:添加前交易日涨停基因、当日交易日涨停基因和涨停基因差 filtered_data['前交易日涨停基因'] = filtered_data.groupby('证券代码')['涨停基因'].shift(1).fillna(0) filtered_data['当日交易日涨停基因'] = filtered_data['涨停基因'] filtered_data['涨停基因差'] = filtered_data['当日交易日涨停基因'] - filtered_data['前交易日涨停基因'] # 确保所有新列为数值类型 filtered_data['前交易日涨停基因'] = pd.to_numeric(filtered_data['前交易日涨停基因'], errors='coerce').fillna(0) filtered_data['当日交易日涨停基因'] = pd.to_numeric(filtered_data['当日交易日涨停基因'], errors='coerce').fillna(0) filtered_data['涨停基因差'] = pd.to_numeric(filtered_data['涨停基因差'], errors='coerce').fillna(0) # Reorder columns as per user requirement desired_columns = [ '日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入', '前交易日涨停基因', '当日交易日涨停基因', '涨停基因差' ] # 检查是否存在所有需要的列 missing_columns = [col for col in desired_columns if col not in filtered_data.columns] if missing_columns: print(f"警告:缺少列 {missing_columns},无法添加至输出文件中。") # 为缺失的列添加NaN for col in missing_columns: filtered_data[col] = pd.NA # 选择需要的列 output_data = filtered_data[desired_columns] # 步骤5:将数据输出到新的CSV文件(请根据实际路径修改) output_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv" try: # 在排序步骤中,保持按证券代码和日期排序 output_data = output_data.sort_values(by=['证券代码', '日期']) # 将“日期”列转换为字符串格式(如 'dd/mm/yyyy') output_data['日期'] = output_data['日期'].dt.strftime('%d/%m/%Y') # 保存到CSV文件 output_data.to_csv(output_csv_path, index=False, encoding='gbk') print(f"\n数据已成功写入:{output_csv_path}") except Exception as e: print(f"写入输出CSV文件时出错:{e}") if __name__ == "__main__": main()
移除步骤5中的单独按日期排序:
output_data
仅按 ['日期']
进行了排序,这会打乱 ['证券代码', '日期']
的初始排序。['证券代码', '日期']
的排序:
pythonoutput_data = output_data.sort_values(by=['证券代码', '日期'])
确保在转换日期格式之前完成所有排序操作:
日期
列转换为字符串格式之前,已经按 ['证券代码', '日期']
进行了排序,确保排序的准确性。处理 涨停基因差
计算中的缺失值:
fillna(0)
来处理缺失值,避免在计算过程中出现 NaN
或非数值的问题。确保所有需要的列都存在:
NaN
,避免在输出时出错。#VALUE!
的处理在您的输出数据中出现了 #VALUE!
,这通常是由于某些单元格中的数据格式不正确或存在错误。以下是一些可能的原因及解决方案:
非数值数据:
涨停基因差
)时,所有参与计算的列都是数值类型。如果有非数值数据,使用 pd.to_numeric
并设置 errors='coerce'
将其转换为 NaN
,然后使用 fillna(0)
填充。Excel 打开CSV文件时的自动转换:
#VALUE!
。您可以尝试以下方法:
调试数据:
pythonprint(output_data[['前交易日涨停基因', '当日交易日涨停基因', '涨停基因差']].head())
['证券代码', '日期']
进行排序,避免多次排序导致的混乱。通过以上修改,您的数据应该能够按照预期的顺序进行排序,并且避免出现 #VALUE!
这样的错误。如果在修改后仍然遇到问题,请提供更多详细信息,以便进一步协助您解决问题。
1.增加不同股票代码的分隔行
以
日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差
作分隔 2,每次要保存数据的文件先 清除已有的保存数据,再重新写入新的数据作保存 要完整的代码
为了满足您的需求,我已经在代码中增加了不同股票代码之间的分隔行,并确保每次保存文件前会清除已有的数据。以下是完整的修改后的代码:
pythonimport pandas as pd import os import re from io import StringIO def determine_suffix(stock_code): """ 根据股票代码确定后缀。 以'6'开头的代码添加'.SH',其他的添加'.SZ'。 """ if stock_code.startswith('6'): return '.SH' else: return '.SZ' def process_stock_codes(input_codes): """ 处理输入的股票代码,确保它们具有正确的后缀。 """ processed_codes = [] for code in input_codes: # 去除空白、换行和逗号,并转换为大写 code = code.strip().upper().replace(',', '').replace('\n', '').replace('\r', '') if not code: continue # 跳过空字符串 if '.' in code: # 确保后缀为.SH或.SZ parts = code.split('.') if len(parts) != 2 or parts[1] not in ['SH', 'SZ']: print(f"股票代码 {code} 的后缀无效。跳过。") continue processed_codes.append(code) else: suffix = determine_suffix(code) full_code = f"{code}{suffix}" processed_codes.append(full_code) return processed_codes def main(): # 步骤1:读取输入CSV文件(请根据实际路径修改) input_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\openai-东方 - 涨停池20231214.csv" if not os.path.exists(input_csv_path): print(f"未找到输入CSV文件:{input_csv_path}") return try: with open(input_csv_path, 'r', encoding='gbk') as f: lines = f.readlines() # 过滤掉以“日期:”开头的行和空行 data_lines = [] header_set = False # 使用逗号分隔符匹配表头行 header_line_pattern = re.compile(r'^日期,证券代码') for line in lines: if line.startswith('日期:'): # 跳过以"日期:"开头的注释行 continue if line.strip() == '': # 跳过空行 continue if header_line_pattern.match(line): # 如果匹配到表头行且还未设置表头,则保留 if not header_set: data_lines.append(line) header_set = True else: # 已有表头则跳过后面的表头行 continue else: data_lines.append(line) if not header_set: print("未找到有效的表头信息。请检查CSV文件格式。") print("请确保CSV文件中包含类似 '日期,证券代码,...' 的表头行。") # 调试信息:打印前10行过滤后的数据 print("CSV文件的前10行(去除注释和空行):") print('\n'.join(data_lines[:10])) return # 将过滤后的数据行合并为一个字符串 data_str = ''.join(data_lines) # 使用StringIO读取过滤后的数据,并使用逗号作为分隔符 df = pd.read_csv(StringIO(data_str), sep=',', encoding='gbk', dayfirst=True) # 清理列名:去除前后空格并转换为大写 df.columns = df.columns.str.strip().str.upper() # 检查是否存在“证券代码”列 if '证券代码' not in df.columns: print("CSV文件中不包含 '证券代码' 列。请检查列名是否正确。") print("当前列名:", df.columns.tolist()) return # 确保“日期”列为日期类型 df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') # 检查是否有未解析的日期 if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") # 确保“涨停基因”列为数值类型,处理非数值数据 df['涨停基因'] = pd.to_numeric(df['涨停基因'], errors='coerce') # 调试打印数据预览 print("清理后的列名:", df.columns.tolist()) print("数据预览(前5行):") print(df.head()) except Exception as e: print(f"读取输入CSV文件时出错:{e}") return # 步骤2:获取用户输入的股票代码(支持多行输入) print("\n请输入一个或多个股票代码,使用逗号、空格或换行符分隔。") print("输入完成后请按回车换行,再按一次回车结束输入。") print("示例:") print(" - 单行:603278.SH 或 603278,300220,002086.SZ") print(" - 多行:可多行输入代码,每行一个或多个代码,完成后输入空行结束。") # 读取多行输入,直到用户输入空行 input_lines = [] while True: try: line = input() if line.strip() == '': break input_lines.append(line) except EOFError: break # 将多行输入合并为一个字符串 user_input = ' '.join(input_lines) # 使用正则表达式分割输入,支持逗号、空格和换行符 input_codes = re.split(r'[,\s]+', user_input) # 处理股票代码,确保格式正确 stock_codes = process_stock_codes(input_codes) # 调试信息:打印拆分后的代码列表和处理后的股票代码列表 print("\n拆分后的代码列表:", input_codes) print("处理后的股票代码列表:", stock_codes) if not stock_codes: print("未输入有效的股票代码。退出。") return print(f"\n处理后的股票代码:{stock_codes}") # 确保“证券代码”列为字符串类型并转换为大写 df['证券代码'] = df['证券代码'].astype(str).str.upper() # 步骤3:根据股票代码过滤数据 filtered_data = df[df['证券代码'].isin(stock_codes)].copy() if filtered_data.empty: print("未找到输入股票代码的相关数据。") return # 按证券代码和日期排序 filtered_data = filtered_data.sort_values(by=['证券代码', '日期']) # 步骤4:添加前交易日涨停基因、当日交易日涨停基因和涨停基因差 filtered_data['前交易日涨停基因'] = filtered_data.groupby('证券代码')['涨停基因'].shift(1).fillna(0) filtered_data['当日交易日涨停基因'] = filtered_data['涨停基因'] filtered_data['涨停基因差'] = filtered_data['当日交易日涨停基因'] - filtered_data['前交易日涨停基因'] # 确保所有新列为数值类型 filtered_data['前交易日涨停基因'] = pd.to_numeric(filtered_data['前交易日涨停基因'], errors='coerce').fillna(0) filtered_data['当日交易日涨停基因'] = pd.to_numeric(filtered_data['当日交易日涨停基因'], errors='coerce').fillna(0) filtered_data['涨停基因差'] = pd.to_numeric(filtered_data['涨停基因差'], errors='coerce').fillna(0) # Reorder columns as per user requirement desired_columns = [ '日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入', '前交易日涨停基因', '当日交易日涨停基因', '涨停基因差' ] # 检查是否存在所有需要的列 missing_columns = [col for col in desired_columns if col not in filtered_data.columns] if missing_columns: print(f"警告:缺少列 {missing_columns},无法添加至输出文件中。") # 为缺失的列添加NaN for col in missing_columns: filtered_data[col] = pd.NA # 选择需要的列 output_data = filtered_data[desired_columns] # 步骤5:添加分隔行 output_data_sorted = output_data.sort_values(by=['证券代码', '日期']) separator = pd.DataFrame([desired_columns], columns=desired_columns) grouped = output_data_sorted.groupby('证券代码') output_with_separators = pd.concat([group.append(separator, ignore_index=True) for name, group in grouped], ignore_index=True) output_with_separators = output_with_separators[:-1] # 移除最后多余的分隔行 # 步骤6:将数据输出到新的CSV文件(请根据实际路径修改) output_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv" try: # 清除已有的文件内容 with open(output_csv_path, 'w', encoding='gbk') as f: pass # 将“日期”列转换为字符串格式(如 'dd/mm/yyyy') output_with_separators['日期'] = pd.to_datetime(output_with_separators['日期'], errors='coerce').dt.strftime('%d/%m/%Y') # 保存到CSV文件,不包含索引 output_with_separators.to_csv(output_csv_path, index=False, encoding='gbk', header=False) # 手动写入分隔行的表头 with open(output_csv_path, 'r+', encoding='gbk') as f: content = f.read() f.seek(0, 0) f.write('\t'.join(desired_columns) + '\n' + content) print(f"\n数据已成功写入:{output_csv_path}") except Exception as e: print(f"写入输出CSV文件时出错:{e}") if __name__ == "__main__": main()
添加分隔行:
groupby
按证券代码
分组,然后在每组之间插入表头作为分隔行。清除已有数据后保存新数据:
with open(output_csv_path, 'w', encoding='gbk') as f: pass
清空文件内容。header=False
,然后手动在文件顶部写入表头,确保每个分隔行都有表头。通过这些修改,最终生成的CSV文件将在不同股票代码的数据之间插入表头作为分隔,并且每次运行脚本时都会清除旧数据,确保输出文件仅包含最新的数据。
C:\Users\minus\anaconda3\envs\PY310\python.exe "C:/Users/minus/Desktop/crawl_stock_date/OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.py"
警告:有些日期未能正确解析。请检查日期格式。
清理后的列名: ['日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入']
数据预览(前5行):
日期 证券代码 证券简称 ... 封板额 换手率 净流入
0 2022-08-17 002272.SZ 川润股份 ... 1.678189e+08 10.7051 58220233.0
1 2022-08-17 002553.SZ 南方精工 ... 6.555033e+07 46.1626 -3648272.0
2 2022-08-17 002337.SZ 赛象科技 ... 5.284706e+07 14.5235 154757029.0
3 2022-08-17 002482.SZ *ST广田 ... 4.390453e+06 2.9117 29487611.0
4 2022-08-17 301021.SZ 英诺激光 ... 2.392014e+07 14.4313 15418632.0
[5 rows x 13 columns]
请输入一个或多个股票代码,使用逗号、空格或换行符分隔。
输入完成后请按回车换行,再按一次回车结束输入。
示例:
拆分后的代码列表: ['600796', '300840', '600172', '000903', '002526', '603278', '605179', '002347', '002193', '002593', '002031', '603662', '002131', '002195', '002640', '600889', '300607', '003041']
处理后的股票代码列表: ['600796.SH', '300840.SZ', '600172.SH', '000903.SZ', '002526.SZ', '603278.SH', '605179.SH', '002347.SZ', '002193.SZ', '002593.SZ', '002031.SZ', '603662.SH', '002131.SZ', '002195.SZ', '002640.SZ', '600889.SH', '300607.SZ', '003041.SZ']
处理后的股票代码:['600796.SH', '300840.SZ', '600172.SH', '000903.SZ', '002526.SZ', '603278.SH', '605179.SH', '002347.SZ', '002193.SZ', '002593.SZ', '002031.SZ', '603662.SH', '002131.SZ', '002195.SZ', '002640.SZ', '600889.SH', '300607.SZ', '003041.SZ']
C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.py:199: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
output_with_separators = pd.concat([group.append(separator, ignore_index=True) for name, group in grouped], ignore_index=True)
数据已成功写入:C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv
Process finished with exit code 0
您好!感谢您提供详细的运行日志和代码输出信息。根据您提供的内容,我注意到以下几点需要处理:
日期解析警告:
警告:有些日期未能正确解析。请检查日期格式。
这表示在您的数据中,有些日期无法被正确解析为日期类型。尽管在数据预览中大部分日期看起来正常,但可能存在格式不一致或异常的日期值。
FutureWarning 警告:
FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
这是因为 DataFrame.append
方法在未来的 pandas 版本中将被移除,建议使用 pandas.concat
代替。
为了优化您的脚本,并解决上述警告,我将提供以下修改建议和完整的代码:
FutureWarning
警告您在添加分隔行时使用了 group.append(separator, ignore_index=True)
,这会触发 FutureWarning
。我们可以使用 pd.concat
直接合并数据帧来替代 append
方法。
确保所有日期格式一致,并处理可能的异常日期格式。可以在日期解析时更严格地指定日期格式,或者在读取数据之前清洗日期列。
在不同股票代码的数据之间添加分隔行(表头),可以通过分组后进行拼接来实现。以下代码示例展示了如何实现这一点,并确保新文件写入前清空旧数据。
pythonimport pandas as pd import os import re from io import StringIO def determine_suffix(stock_code): """ 根据股票代码确定后缀。 以'6'开头的代码添加'.SH',其他的添加'.SZ'。 """ if stock_code.startswith('6'): return '.SH' else: return '.SZ' def process_stock_codes(input_codes): """ 处理输入的股票代码,确保它们具有正确的后缀。 """ processed_codes = [] for code in input_codes: # 去除空白、换行和逗号,并转换为大写 code = code.strip().upper().replace(',', '').replace('\n', '').replace('\r', '') if not code: continue # 跳过空字符串 if '.' in code: # 确保后缀为.SH或.SZ parts = code.split('.') if len(parts) != 2 or parts[1] not in ['SH', 'SZ']: print(f"股票代码 {code} 的后缀无效。跳过。") continue processed_codes.append(code) else: suffix = determine_suffix(code) full_code = f"{code}{suffix}" processed_codes.append(full_code) return processed_codes def main(): # 步骤1:读取输入CSV文件(请根据实际路径修改) input_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\openai-东方 - 涨停池20231214.csv" if not os.path.exists(input_csv_path): print(f"未找到输入CSV文件:{input_csv_path}") return try: with open(input_csv_path, 'r', encoding='gbk') as f: lines = f.readlines() # 过滤掉以“日期:”开头的行和空行 data_lines = [] header_set = False # 使用逗号分隔符匹配表头行 header_line_pattern = re.compile(r'^日期,证券代码') for line in lines: if line.startswith('日期:'): # 跳过以"日期:"开头的注释行 continue if line.strip() == '': # 跳过空行 continue if header_line_pattern.match(line): # 如果匹配到表头行且还未设置表头,则保留 if not header_set: data_lines.append(line) header_set = True else: # 已有表头则跳过后面的表头行 continue else: data_lines.append(line) if not header_set: print("未找到有效的表头信息。请检查CSV文件格式。") print("请确保CSV文件中包含类似 '日期,证券代码,...' 的表头行。") # 调试信息:打印前10行过滤后的数据 print("CSV文件的前10行(去除注释和空行):") print('\n'.join(data_lines[:10])) return # 将过滤后的数据行合并为一个字符串 data_str = ''.join(data_lines) # 使用StringIO读取过滤后的数据,并使用逗号作为分隔符 df = pd.read_csv(StringIO(data_str), sep=',', encoding='gbk', dayfirst=True) # 清理列名:去除前后空格并转换为大写 df.columns = df.columns.str.strip().str.upper() # 检查是否存在“证券代码”列 if '证券代码' not in df.columns: print("CSV文件中不包含 '证券代码' 列。请检查列名是否正确。") print("当前列名:", df.columns.tolist()) return # 确保“日期”列为日期类型 # 尝试更严格地解析日期格式,例如指定格式为 'dd/mm/yyyy' 或 'yyyy-mm-dd' # 这里假设日期格式为 'dd/mm/yyyy',根据实际情况调整 try: df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, format='%d/%m/%Y', errors='coerce') except Exception as e: print(f"日期解析时出错:{e}") df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') # 检查是否有未解析的日期 if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") # 显示无法解析的日期值 invalid_dates = df[df['日期'].isnull()]['日期'] print("无法解析的日期值:") print(invalid_dates.unique()) # 确保“涨停基因”列为数值类型,处理非数值数据 df['涨停基因'] = pd.to_numeric(df['涨停基因'], errors='coerce') # 调试打印数据预览 print("清理后的列名:", df.columns.tolist()) print("数据预览(前5行):") print(df.head()) except Exception as e: print(f"读取输入CSV文件时出错:{e}") return # 步骤2:获取用户输入的股票代码(支持多行输入) print("\n请输入一个或多个股票代码,使用逗号、空格或换行符分隔。") print("输入完成后请按回车换行,再按一次回车结束输入。") print("示例:") print(" - 单行:603278.SH 或 603278,300220,002086.SZ") print(" - 多行:可多行输入代码,每行一个或多个代码,完成后输入空行结束。") # 读取多行输入,直到用户输入空行 input_lines = [] while True: try: line = input() if line.strip() == '': break input_lines.append(line) except EOFError: break # 将多行输入合并为一个字符串 user_input = ' '.join(input_lines) # 使用正则表达式分割输入,支持逗号、空格和换行符 input_codes = re.split(r'[,\s]+', user_input) # 处理股票代码,确保格式正确 stock_codes = process_stock_codes(input_codes) # 调试信息:打印拆分后的代码列表和处理后的股票代码列表 print("\n拆分后的代码列表:", input_codes) print("处理后的股票代码列表:", stock_codes) if not stock_codes: print("未输入有效的股票代码。退出。") return print(f"\n处理后的股票代码:{stock_codes}") # 确保“证券代码”列为字符串类型并转换为大写 df['证券代码'] = df['证券代码'].astype(str).str.upper() # 步骤3:根据股票代码过滤数据 filtered_data = df[df['证券代码'].isin(stock_codes)].copy() if filtered_data.empty: print("未找到输入股票代码的相关数据。") return # 按证券代码和日期排序 filtered_data = filtered_data.sort_values(by=['证券代码', '日期']) # 步骤4:添加前交易日涨停基因、当日交易日涨停基因和涨停基因差 filtered_data['前交易日涨停基因'] = filtered_data.groupby('证券代码')['涨停基因'].shift(1).fillna(0) filtered_data['当日交易日涨停基因'] = filtered_data['涨停基因'] filtered_data['涨停基因差'] = filtered_data['当日交易日涨停基因'] - filtered_data['前交易日涨停基因'] # 确保所有新列为数值类型 filtered_data['前交易日涨停基因'] = pd.to_numeric(filtered_data['前交易日涨停基因'], errors='coerce').fillna(0) filtered_data['当日交易日涨停基因'] = pd.to_numeric(filtered_data['当日交易日涨停基因'], errors='coerce').fillna(0) filtered_data['涨停基因差'] = pd.to_numeric(filtered_data['涨停基因差'], errors='coerce').fillna(0) # Reorder columns as per user requirement desired_columns = [ '日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入', '前交易日涨停基因', '当日交易日涨停基因', '涨停基因差' ] # 检查是否存在所有需要的列 missing_columns = [col for col in desired_columns if col not in filtered_data.columns] if missing_columns: print(f"警告:缺少列 {missing_columns},无法添加至输出文件中。") # 为缺失的列添加NaN for col in missing_columns: filtered_data[col] = pd.NA # 选择需要的列 output_data = filtered_data[desired_columns] # 步骤5:添加分隔行 # 创建分隔行(表头) separator = pd.DataFrame([desired_columns], columns=desired_columns) # 按证券代码分组并在每组之间插入分隔行 grouped = output_data.sort_values(by=['证券代码', '日期']).groupby('证券代码') # 使用列表存储各组数据和分隔行 output_list = [] for name, group in grouped: output_list.append(group) output_list.append(separator) # 添加分隔行 # 合并所有数据帧 output_with_separators = pd.concat(output_list, ignore_index=True) # 移除最后一个多余的分隔行 if output_with_separators.iloc[-1].tolist() == desired_columns: output_with_separators = output_with_separators[:-1] # 步骤6:将数据输出到新的CSV文件(请根据实际路径修改) output_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv" try: # 确保输出目录存在 os.makedirs(os.path.dirname(output_csv_path), exist_ok=True) # 将“日期”列转换为字符串格式(如 'dd/mm/yyyy') output_with_separators['日期'] = pd.to_datetime(output_with_separators['日期'], errors='coerce').dt.strftime('%d/%m/%Y') # 保存到CSV文件,不包含索引和表头 output_with_separators.to_csv(output_csv_path, index=False, encoding='gbk', header=False) print(f"\n数据已成功写入:{output_csv_path}") except Exception as e: print(f"写入输出CSV文件时出错:{e}") if __name__ == "__main__": main()
替换 append
方法:
python# 原代码使用 append 方法,触发 FutureWarning # output_with_separators = pd.concat([group.append(separator, ignore_index=True) for name, group in grouped], ignore_index=True) # 修改后使用 pd.concat 直接合并数据帧 output_with_separators = pd.concat(output_list, ignore_index=True)
通过将各组数据和分隔行存储在 output_list
列表中,然后使用 pd.concat
一次性合并,避免使用被弃用的 append
方法。
处理日期解析警告:
pd.to_datetime
中指定 format
参数,可以提高解析的准确性。pythontry: df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, format='%d/%m/%Y', errors='coerce') except Exception as e: print(f"日期解析时出错:{e}") df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") # 显示无法解析的日期值 invalid_dates = df[df['日期'].isnull()]['日期'] print("无法解析的日期值:") print(invalid_dates.unique())
根据实际的日期格式(如 dd/mm/yyyy
或 yyyy-mm-dd
),调整 format
参数。如果不确定,可以先尝试不指定格式,让 pandas
尝试自动解析。
确保输出目录存在: 在保存文件之前,确保输出目录存在,避免因路径不存在而导致的错误。
pythonos.makedirs(os.path.dirname(output_csv_path), exist_ok=True)
优化分隔行添加逻辑: 通过分组后依次添加数据和分隔行,确保不同股票代码的数据之间有清晰的分隔。
pythonoutput_list = [] for name, group in grouped: output_list.append(group) output_list.append(separator) # 添加分隔行 # 合并所有数据帧 output_with_separators = pd.concat(output_list, ignore_index=True) # 移除最后一个多余的分隔行 if output_with_separators.iloc[-1].tolist() == desired_columns: output_with_separators = output_with_separators[:-1]
转换日期格式前确保日期列存在:
在将 日期
列转换为字符串格式之前,确保所有日期已正确解析。
pythonoutput_with_separators['日期'] = pd.to_datetime(output_with_separators['日期'], errors='coerce').dt.strftime('%d/%m/%Y')
日期解析警告:如果有些日期格式不正确或存在异常值,脚本会在控制台打印出这些无法解析的日期值,您可以根据这些信息进一步清洗或修正原始数据。
分隔行:在输出的 CSV 文件中,不同股票代码的数据之间会插入一行表头作为分隔,便于阅读和区分。
FutureWarning 消失:通过替换 append
方法,FutureWarning
将不再出现。
验证输出 CSV 文件: 在打开输出的 CSV 文件时,确保分隔行(表头)不会影响后续的数据处理或导入。如果需要进一步处理数据,可以考虑使用 Excel 或其他工具进行预处理。
数据清洗: 确保原始 CSV 文件中的日期格式一致,避免因格式不一致导致的解析问题。如果数据量较大,建议使用脚本批量处理异常日期。
代码优化: 您可以将重复使用的代码段封装成函数,以提高代码的可维护性和可读性。
如果您在运行修改后的脚本时遇到任何问题,或有其他需求,请随时告知!
保存数据又出现问题了,1.第一行 没有 日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差 2.好多列出现没有相关日期 ,3.部分行的 日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差 相关不完整
非常抱歉您在运行脚本时遇到了问题。根据您的描述,主要问题包括:
这些问题可能源于以下几个方面:
为了彻底解决这些问题,我将为您提供一个优化后的完整代码,确保:
pythonimport pandas as pd import os import re from io import StringIO def determine_suffix(stock_code): """ 根据股票代码确定后缀。 以'6'开头的代码添加'.SH',其他的添加'.SZ'。 """ if stock_code.startswith('6'): return '.SH' else: return '.SZ' def process_stock_codes(input_codes): """ 处理输入的股票代码,确保它们具有正确的后缀。 """ processed_codes = [] for code in input_codes: # 去除空白、换行和逗号,并转换为大写 code = code.strip().upper().replace(',', '').replace('\n', '').replace('\r', '') if not code: continue # 跳过空字符串 if '.' in code: # 确保后缀为.SH或.SZ parts = code.split('.') if len(parts) != 2 or parts[1] not in ['SH', 'SZ']: print(f"股票代码 {code} 的后缀无效。跳过。") continue processed_codes.append(code) else: suffix = determine_suffix(code) full_code = f"{code}{suffix}" processed_codes.append(full_code) return processed_codes def main(): # 步骤1:读取输入CSV文件(请根据实际路径修改) input_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\openai-东方 - 涨停池20231214.csv" if not os.path.exists(input_csv_path): print(f"未找到输入CSV文件:{input_csv_path}") return try: with open(input_csv_path, 'r', encoding='gbk') as f: lines = f.readlines() # 过滤掉以“日期:”开头的行和空行 data_lines = [] header_set = False # 使用逗号分隔符匹配表头行 header_line_pattern = re.compile(r'^日期,证券代码') for line in lines: if line.startswith('日期:'): # 跳过以"日期:"开头的注释行 continue if line.strip() == '': # 跳过空行 continue if header_line_pattern.match(line): # 如果匹配到表头行且还未设置表头,则保留 if not header_set: header_line = line.strip() header_set = True else: # 已有表头则跳过后面的表头行 continue else: data_lines.append(line) if not header_set: print("未找到有效的表头信息。请检查CSV文件格式。") print("请确保CSV文件中包含类似 '日期,证券代码,...' 的表头行。") # 调试信息:打印前10行过滤后的数据 print("CSV文件的前10行(去除注释和空行):") print('\n'.join(data_lines[:10])) return # 将过滤后的数据行合并为一个字符串 data_str = ''.join(data_lines) # 使用StringIO读取过滤后的数据,并使用逗号作为分隔符 df = pd.read_csv(StringIO(data_str), sep=',', encoding='gbk', dayfirst=True) # 清理列名:去除前后空格并转换为大写 df.columns = df.columns.str.strip().str.upper() # 检查是否存在“证券代码”列 if '证券代码' not in df.columns: print("CSV文件中不包含 '证券代码' 列。请检查列名是否正确。") print("当前列名:", df.columns.tolist()) return # 保留原始日期字符串以便后续调试 original_dates = df['日期'].astype(str).copy() # 确保“日期”列为日期类型 # 尝试更严格地解析日期格式,例如指定格式为 'dd/mm/yyyy' 或 'yyyy-mm-dd' # 这里先尝试自动解析 df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') # 检查是否有未解析的日期 if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") # 显示无法解析的日期值 invalid_dates = original_dates[df['日期'].isnull()].unique() print("无法解析的日期值:") print(invalid_dates) # 确保“涨停基因”列为数值类型,处理非数值数据 df['涨停基因'] = pd.to_numeric(df['涨停基因'], errors='coerce').fillna(0) # 调试打印数据预览 print("清理后的列名:", df.columns.tolist()) print("数据预览(前5行):") print(df.head()) except Exception as e: print(f"读取输入CSV文件时出错:{e}") return # 步骤2:获取用户输入的股票代码(支持多行输入) print("\n请输入一个或多个股票代码,使用逗号、空格或换行符分隔。") print("输入完成后请按回车换行,再按一次回车结束输入。") print("示例:") print(" - 单行:603278.SH 或 603278,300220,002086.SZ") print(" - 多行:可多行输入代码,每行一个或多个代码,完成后输入空行结束。") # 读取多行输入,直到用户输入空行 input_lines = [] while True: try: line = input() if line.strip() == '': break input_lines.append(line) except EOFError: break # 将多行输入合并为一个字符串 user_input = ' '.join(input_lines) # 使用正则表达式分割输入,支持逗号、空格和换行符 input_codes = re.split(r'[,\s]+', user_input) # 处理股票代码,确保格式正确 stock_codes = process_stock_codes(input_codes) # 调试信息:打印拆分后的代码列表和处理后的股票代码列表 print("\n拆分后的代码列表:", input_codes) print("处理后的股票代码列表:", stock_codes) if not stock_codes: print("未输入有效的股票代码。退出。") return print(f"\n处理后的股票代码:{stock_codes}") # 确保“证券代码”列为字符串类型并转换为大写 df['证券代码'] = df['证券代码'].astype(str).str.upper() # 步骤3:根据股票代码过滤数据 filtered_data = df[df['证券代码'].isin(stock_codes)].copy() if filtered_data.empty: print("未找到输入股票代码的相关数据。") return # 按证券代码和日期排序 filtered_data = filtered_data.sort_values(by=['证券代码', '日期']) # 步骤4:添加前交易日涨停基因、当日交易日涨停基因和涨停基因差 filtered_data['前交易日涨停基因'] = filtered_data.groupby('证券代码')['涨停基因'].shift(1).fillna(0) filtered_data['当日交易日涨停基因'] = filtered_data['涨停基因'] filtered_data['涨停基因差'] = filtered_data['当日交易日涨停基因'] - filtered_data['前交易日涨停基因'] # 确保所有新列为数值类型 filtered_data['前交易日涨停基因'] = pd.to_numeric(filtered_data['前交易日涨停基因'], errors='coerce').fillna(0) filtered_data['当日交易日涨停基因'] = pd.to_numeric(filtered_data['当日交易日涨停基因'], errors='coerce').fillna(0) filtered_data['涨停基因差'] = pd.to_numeric(filtered_data['涨停基因差'], errors='coerce').fillna(0) # Reorder columns as per user requirement desired_columns = [ '日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入', '前交易日涨停基因', '当日交易日涨停基因', '涨停基因差' ] # 检查是否存在所有需要的列 missing_columns = [col for col in desired_columns if col not in filtered_data.columns] if missing_columns: print(f"警告:缺少列 {missing_columns},无法添加至输出文件中。") # 为缺失的列添加NaN for col in missing_columns: filtered_data[col] = pd.NA # 选择需要的列 output_data = filtered_data[desired_columns] # 步骤5:添加分隔行 # 创建分隔行(表头) separator = desired_columns # 初始化输出行列表,并添加表头作为第一行 output_lines = [] header_str = '\t'.join(desired_columns) output_lines.append(header_str) # 按证券代码分组并在每组之间插入分隔行 grouped = output_data.sort_values(by=['证券代码', '日期']).groupby('证券代码') for name, group in grouped: # 确保 '日期' 列已格式化为 'dd/mm/yyyy' group['日期'] = group['日期'].dt.strftime('%d/%m/%Y').fillna('') # Convert group DataFrame to string with tab separator, no header, no index group_str = group.to_csv(sep='\t', index=False, header=False, encoding='gbk') output_lines.append(group_str.strip()) # 移除末尾的换行符 # Append separator row (header) output_lines.append(header_str) # 移除最后一个多余的分隔行 if output_lines[-1] == header_str: output_lines.pop() # 将所有行合并为一个字符串 final_output_str = '\n'.join(output_lines) # 步骤6:将数据输出到新的CSV文件(请根据实际路径修改) output_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv" try: # 确保输出目录存在 os.makedirs(os.path.dirname(output_csv_path), exist_ok=True) # 写入数据到CSV文件 with open(output_csv_path, 'w', encoding='gbk') as f: f.write(final_output_str) print(f"\n数据已成功写入:{output_csv_path}") except Exception as e: print(f"写入输出CSV文件时出错:{e}") if __name__ == "__main__": main()
确保输出文件第一行包含表头:
output_lines
列表,并将表头字符串 header_str
添加为第一行。格式化日期:
日期
列已格式化为 'dd/mm/yyyy'
,并使用 .fillna('')
处理缺失的日期。NaT
或空值,从而确保日期列的数据完整性。插入分隔行:
header_str
。移除多余的最后一个分隔行:
output_lines
的最后一行是否为分隔行(表头),如果是,则将其移除,避免文件末尾多出一个不必要的分隔行。统一使用制表符作为分隔符:
'\t'
作为分隔符,这与您提供的输出数据一致。处理缺失列:
filtered_data
中添加这些列,并用 NaN
填充,以确保输出文件的完整性。错误处理和调试信息:
print
语句,用于输出调试信息,帮助您了解脚本的执行状态。输出文件的第一行包含完整的表头:
日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差
每个不同证券代码的数据之间插入一个表头作为分隔行,例如:
text日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差 12/6/2024 002031.SZ 巨轮智能 2.44 9.90990991 专用设备 65.75 今日首板 9:40:15 25425900 62039196 3.4382 80873602 0 65.75 0 13/12/2023 002031.SZ 巨轮智能 4.27 10.05154639 专用设备 66.75 今日首板 13:48:33 27951100 119351197 22.1947 574851033 65.75 66.75 1 ... 日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差 10/2/2023 002131.SZ 利欧股份 2.08 10.05291005 互联网服务 58.75 今日首板 13:32:30 26253097 54606441.76 6.8428 226817620 0 58.75 0 17/6/2024 002131.SZ 利欧股份 1.5 10.29411765 互联网服务 59.75 今日首板 14:38:33 14423048 21634572 8.2001 85836178 58.75 59.75 1 ...
所有数据行完整且包含所有必要的列,避免出现部分行数据不完整的情况。
数据清洗:
日志记录:
代码优化:
测试与验证:
通过上述优化,您的脚本应能正确生成包含表头的输出文件,并在不同证券代码的数据之间插入分隔行,确保数据的完整性和可读性。如果在运行优化后的脚本时仍遇到问题,请提供更多详细的错误信息或示例数据,以便进一步协助您解决问题。
如果您有任何其他问题或需要进一步的帮助,请随时告知!
import pandas as pd
import os
import re
from io import StringIO
def determine_suffix(stock_code):
"""
根据股票代码确定后缀。
以'6'开头的代码添加'.SH',其他的添加'.SZ'。
"""
if stock_code.startswith('6'):
return '.SH'
else:
return '.SZ'
def process_stock_codes(input_codes):
"""
处理输入的股票代码,确保它们具有正确的后缀。
"""
processed_codes = []
for code in input_codes:
# 去除空白、换行和逗号,并转换为大写
code = code.strip().upper().replace(',', '').replace('\n', '').replace('\r', '')
if not code:
continue # 跳过空字符串
if '.' in code:
# 确保后缀为.SH或.SZ
parts = code.split('.')
if len(parts) != 2 or parts[1] not in ['SH', 'SZ']:
print(f"股票代码 {code} 的后缀无效。跳过。")
continue
processed_codes.append(code)
else:
suffix = determine_suffix(code)
full_code = f"{code}{suffix}"
processed_codes.append(full_code)
return processed_codes
def main():
# 步骤1:读取输入CSV文件(请根据实际路径修改)
input_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\openai-东方 - 涨停池20231214.csv"
textif not os.path.exists(input_csv_path): print(f"未找到输入CSV文件:{input_csv_path}") return try: with open(input_csv_path, 'r', encoding='gbk') as f: lines = f.readlines() # 过滤掉以“日期:”开头的行和空行 data_lines = [] header_set = False # 使用逗号分隔符匹配表头行 header_line_pattern = re.compile(r'^日期,证券代码') for line in lines: if line.startswith('日期:'): # 跳过以"日期:"开头的注释行 continue if line.strip() == '': # 跳过空行 continue if header_line_pattern.match(line): # 如果匹配到表头行且还未设置表头,则保留 if not header_set: data_lines.append(line) header_set = True else: # 已有表头则跳过后面的表头行 continue else: data_lines.append(line) if not header_set: print("未找到有效的表头信息。请检查CSV文件格式。") print("请确保CSV文件中包含类似 '日期,证券代码,...' 的表头行。") # 调试信息:打印前10行过滤后的数据 print("CSV文件的前10行(去除注释和空行):") print('\n'.join(data_lines[:10])) return # 将过滤后的数据行合并为一个字符串 data_str = ''.join(data_lines) # 使用StringIO读取过滤后的数据,并使用逗号作为分隔符 df = pd.read_csv(StringIO(data_str), sep=',', encoding='gbk', dayfirst=True) # 清理列名:去除前后空格并转换为大写 df.columns = df.columns.str.strip().str.upper() # 检查是否存在“证券代码”列 if '证券代码' not in df.columns: print("CSV文件中不包含 '证券代码' 列。请检查列名是否正确。") print("当前列名:", df.columns.tolist()) return # 确保“日期”列为日期类型 # 尝试更严格地解析日期格式,例如指定格式为 'dd/mm/yyyy' 或 'yyyy-mm-dd' # 这里假设日期格式为 'dd/mm/yyyy',根据实际情况调整 try: df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, format='%d/%m/%Y', errors='coerce') except Exception as e: print(f"日期解析时出错:{e}") df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') # 检查是否有未解析的日期 if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") # 显示无法解析的日期值 invalid_dates = df[df['日期'].isnull()]['日期'] print("无法解析的日期值:") print(invalid_dates.unique()) # 确保“涨停基因”列为数值类型,处理非数值数据 df['涨停基因'] = pd.to_numeric(df['涨停基因'], errors='coerce') # 调试打印数据预览 print("清理后的列名:", df.columns.tolist()) print("数据预览(前5行):") print(df.head()) except Exception as e: print(f"读取输入CSV文件时出错:{e}") return # 步骤2:获取用户输入的股票代码(支持多行输入) print("\n请输入一个或多个股票代码,使用逗号、空格或换行符分隔。") print("输入完成后请按回车换行,再按一次回车结束输入。") print("示例:") print(" - 单行:603278.SH 或 603278,300220,002086.SZ") print(" - 多行:可多行输入代码,每行一个或多个代码,完成后输入空行结束。") # 读取多行输入,直到用户输入空行 input_lines = [] while True: try: line = input() if line.strip() == '': break input_lines.append(line) except EOFError: break # 将多行输入合并为一个字符串 user_input = ' '.join(input_lines) # 使用正则表达式分割输入,支持逗号、空格和换行符 input_codes = re.split(r'[,\s]+', user_input) # 处理股票代码,确保格式正确 stock_codes = process_stock_codes(input_codes) # 调试信息:打印拆分后的代码列表和处理后的股票代码列表 print("\n拆分后的代码列表:", input_codes) print("处理后的股票代码列表:", stock_codes) if not stock_codes: print("未输入有效的股票代码。退出。") return print(f"\n处理后的股票代码:{stock_codes}") # 确保“证券代码”列为字符串类型并转换为大写 df['证券代码'] = df['证券代码'].astype(str).str.upper() # 步骤3:根据股票代码过滤数据 filtered_data = df[df['证券代码'].isin(stock_codes)].copy() if filtered_data.empty: print("未找到输入股票代码的相关数据。") return # 按证券代码和日期排序 filtered_data = filtered_data.sort_values(by=['证券代码', '日期']) # 步骤4:添加前交易日涨停基因、当日交易日涨停基因和涨停基因差 filtered_data['前交易日涨停基因'] = filtered_data.groupby('证券代码')['涨停基因'].shift(1).fillna(0) filtered_data['当日交易日涨停基因'] = filtered_data['涨停基因'] filtered_data['涨停基因差'] = filtered_data['当日交易日涨停基因'] - filtered_data['前交易日涨停基因'] # 确保所有新列为数值类型 filtered_data['前交易日涨停基因'] = pd.to_numeric(filtered_data['前交易日涨停基因'], errors='coerce').fillna(0) filtered_data['当日交易日涨停基因'] = pd.to_numeric(filtered_data['当日交易日涨停基因'], errors='coerce').fillna(0) filtered_data['涨停基因差'] = pd.to_numeric(filtered_data['涨停基因差'], errors='coerce').fillna(0) # Reorder columns as per user requirement desired_columns = [ '日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入', '前交易日涨停基因', '当日交易日涨停基因', '涨停基因差' ] # 检查是否存在所有需要的列 missing_columns = [col for col in desired_columns if col not in filtered_data.columns] if missing_columns: print(f"警告:缺少列 {missing_columns},无法添加至输出文件中。") # 为缺失的列添加NaN for col in missing_columns: filtered_data[col] = pd.NA # 选择需要的列 output_data = filtered_data[desired_columns] # 步骤5:添加分隔行 # 创建分隔行(表头) separator = pd.DataFrame([desired_columns], columns=desired_columns) # 按证券代码分组并在每组之间插入分隔行 grouped = output_data.sort_values(by=['证券代码', '日期']).groupby('证券代码') # 使用列表存储各组数据和分隔行 output_list = [] for name, group in grouped: output_list.append(group) output_list.append(separator) # 添加分隔行 # 合并所有数据帧 output_with_separators = pd.concat(output_list, ignore_index=True) # 移除最后一个多余的分隔行 if output_with_separators.iloc[-1].tolist() == desired_columns: output_with_separators = output_with_separators[:-1] # 步骤6:将数据输出到新的CSV文件(请根据实际路径修改) output_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv" try: # 确保输出目录存在 os.makedirs(os.path.dirname(output_csv_path), exist_ok=True) # 将“日期”列转换为字符串格式(如 'dd/mm/yyyy') output_with_separators['日期'] = pd.to_datetime(output_with_separators['日期'], errors='coerce').dt.strftime('%d/%m/%Y') # 保存到CSV文件,不包含索引和表头 output_with_separators.to_csv(output_csv_path, index=False, encoding='gbk', header=False) print(f"\n数据已成功写入:{output_csv_path}") except Exception as e: print(f"写入输出CSV文件时出错:{e}")
if name == "main":
main() 保存数据又出现问题了,1.第一行 没有 日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差 2.好多列出现没有相关日期 ,3.部分行的 日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差 相关不完整 4.再隔多一行,以示分明 10/8/2023 000903.SZ 云内动力 2.82 10.15625 汽车零部件 63.75 今日首板 9:25:00 30219692 85219531.44 1.4182 33012572 0 63.75 63.75
14/8/2023 000903.SZ 云内动力 3.28 10.06711409 汽车零部件 68.25 3天2板 10:09:48 21732110 71281320.8 11.9438 127031468 63.75 68.25 4.5
27/11/2023 000903.SZ 云内动力 2.9 9.848484848 汽车零部件 66.75 今日首板 10:26:06 15832810 45915149 4.6456 77982330 68.25 66.75 -1.5
28/11/2023 000903.SZ 云内动力 3.19 10 汽车零部件 66.5 昨日首板 9:31:15 30861799 98449138.81 4.5601 -5478893 66.75 66.5 -0.25
4/12/2023 000903.SZ 云内动力 3.23 9.863945578 汽车零部件 74.75 6天3板 9:32:33 65764413 212419054 6.103 159885716 66.5 74.75 8.25
5/12/2023 000903.SZ 云内动力 3.55 9.907120743 汽车零部件 75.5 7天4板 10:09:03 30764177 109212828.4 19.752 74261568 74.75 75.5 0.75
29/2/2024 000903.SZ 云内动力 2.34 9.85915493 汽车零部件 73.75 今日首板 13:12:45 12143920 28416772.8 5.3331 56024893 75.5 73.75 -1.75
22/3/2024 000903.SZ 云内动力 2.71 10.16260163 汽车零部件 66.75 今日首板 10:11:54 31781298 86127317.58 6.7239 88966892 73.75 66.75 -7
28/3/2024 000903.SZ 云内动力 2.7 10.20408163 汽车零部件 76.75 今日首板 9:38:18 42906761 115848254.7 3.8757 77543496 66.75 76.75 10
18/9/2024 000903.SZ 云内动力 2.02 9.782608696 汽车零部件 73.75 今日首板 10:07:33 22324481 45095451.62 6.0158 60128376 76.75 73.75 -3
20/9/2024 000903.SZ 云内动力 2.24 9.803921569 汽车零部件 76.5 3天2板 13:18:30 11839400 26520256 9.6602 65838783 73.75 76.5 2.75
22/10/2024 000903.SZ 云内动力 2.37 10.23255814 汽车零部件 73.75 今日首板 14:51:30 5411150 12824425.5 6.4204 34089412 76.5 73.75 -2.75
000903.SZ 云内动力 2.65 9.958506224 汽车零部件 82.5 今日首板 14:16:54 10386200 27523430 9.3438 81645697 73.75 82.5 8.75
000903.SZ 云内动力 2.92 10.18867925 汽车零部件 82.5 6天3板 9:36:03 27125040 79205116.8 8.204 31987908 82.5 82.5 0
000903.SZ 云内动力 3.21 9.931506849 汽车零部件 82.25 7天4板 13:12:30 6829770 21923561.7 18.9991 -57636019 82.5 82.25 -0.25
000903.SZ 云内动力 3.53 9.968847352 汽车零部件 82 8天5板 10:16:15 9395112 33164745.36 9.8071 -60262140 82.25 82 -0.25
000903.SZ 云内动力 4.06 10.02710027 汽车零部件 70.25 3天2板 14:44:12 6711004 27246676.24 17.8143 257586953 82 70.25 -11.75
000903.SZ 云内动力 4.47 10.09852217 汽车零部件 79 4天3板 13:28:39 18488066 82641655.02 19.3582 -128076607 70.25 79 8.75
000903.SZ 云内动力 4.92 10.06711409 汽车零部件 79 5天4板 9:59:06 14505731 71368196.52 13.2886 27379273 79 79 0
证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差
20/9/2022 002031.SZ 巨轮智能 3.36 10.16393443 专用设备 66.75 今日首板 10:07:24 52940600 177880416 14.2956 302947914 0 66.75 66.75
14/12/2022 002031.SZ 巨轮智能 2.99 9.926470588 专用设备 68.75 今日首板 10:09:21 25784207 77094778.93 18.4115 353075358 66.75 68.75 2
20/12/2022 002031.SZ 巨轮智能 3.16 10.10452962 专用设备 74.75 今日首板 10:02:12 39480447 124758212.5 15.539 232397911 68.75 74.75 6
4/1/2023 002031.SZ 巨轮智能 3.62 10.03039514 专用设备 65.5 今日首板 14:06:18 44080619 159571840.8 23.4146 261534123 74.75 65.5 -9.25
30/1/2023 002031.SZ 巨轮智能 3.64 9.96978852 专用设备 64.75 今日首板 11:03:00 17227800 62709192 15.152 272002876 65.5 64.75 -0.75
20/6/2023 002031.SZ 巨轮智能 3.55 9.907120743 专用设备 72.5 今日首板 13:35:36 40072300 142256665 20.8294 380736355 64.75 72.5 7.75
29/6/2023 002031.SZ 巨轮智能 4.07 10 专用设备 75.75 今日首板 9:25:00 103854976 422689752.3 3.9202 162166113 72.5 75.75 3.25
30/6/2023 002031.SZ 巨轮智能 4.48 10.07371007 专用设备 79.5 4天2板 9:37:03 55013167 246458988.2 19.0317 220511752 75.75 79.5 3.75
29/8/2023 002031.SZ 巨轮智能 3.93 10.08403361 专用设备 62.75 今日首板 13:52:18 32076170 126059348.1 17.6858 425925899 79.5 62.75 -16.75
3/11/2023 002031.SZ 巨轮智能 3.51 10.03134796 专用设备 61.75 今日首板 9:25:00 80407995 282232062.5 3.3805 131279882 62.75 61.75 -1
6/11/2023 002031.SZ 巨轮智能 3.86 9.971509972 专用设备 65.5 昨日首板 9:36:48 37889967 146255272.6 14.892 112465124 61.75 65.5 3.75
30/11/2023 002031.SZ 巨轮智能 4.02 10.1369863 专用设备 64.75 今日首板 10:16:57 37418100 150420762 14.8877 283134910 65.5 64.75 -0.75
13/12/2023 002031.SZ 巨轮智能 4.27 10.05154639 专用设备 66.75 今日首板 13:48:33 27951100 119351197 22.1947 574851033 64.75 66.75 2
12/6/2024 002031.SZ 巨轮智能 2.44 9.90990991 专用设备 65.75 今日首板 9:40:15 25425900 62039196 3.4382 80873602 66.75 65.75 -1
18/9/2024 002031.SZ 巨轮智能 2.59 10.21276596 专用设备 68.75 今日首板 13:22:57 11915000 30859850 14.8034 194591484 65.75 68.75 3
18/10/2024 002031.SZ 巨轮智能 3.15 10.13986014 专用设备 68.75 今日首板 9:50:21 25455622 80185209.3 10.4286 234069375 68.75 68.75 0
22/10/2024 002031.SZ 巨轮智能 3.6 10.09174312 专用设备 67.5 3天2板 9:56:54 35587985 128116746 13.2064 283446012 68.75 67.5 -1.25
002031.SZ 巨轮智能 4.11 9.893048128 专用设备 77.5 2天2板 14:21:27 12438250 51121207.5 28.4857 133312624 67.5 77.5 10
002031.SZ 巨轮智能 4.61 10.02386635 专用设备 81.75 6天3板 11:22:15 19279500 88878495 20.7727 432895681 77.5 81.75 4.25
002031.SZ 巨轮智能 4.55 9.903381643 专用设备 70.5 今日首板 14:22:42 33223390 151166424.5 21.4934 374841305 81.75 70.5 -11.25
002031.SZ 巨轮智能 4.68 10.11764706 专用设备 67.75 今日首板 13:16:00 31728015 148487110.2 18.7282 523932919 70.5 67.75 -2.75
002031.SZ 巨轮智能 6.24 10.05291005 专用设备 72 4天4板 9:35:00 36211648 225960683.5 26.2512 31031664 67.75 72 4.25
002031.SZ 巨轮智能 6.86 9.935897436 专用设备 76 5天5板 9:30:39 80788543 554209405 14.9201 2936864 72 76 4
证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差
10/2/2023 002131.SZ 利欧股份 2.08 10.05291005 互联网服务 58.75 今日首板 13:32:30 26253097 54606441.76 6.8428 226817620 0 58.75 58.75
4/5/2023 002131.SZ 利欧股份 2.48 10.22222222 互联网服务 57.5 今日首板 11:07:09 33416958 82874055.84 7.5324 227458567 58.75 57.5 -1.25
17/6/2024 002131.SZ 利欧股份 1.5 10.29411765 互联网服务 59.75 今日首板 14:38:33 14423048 21634572 8.2001 85836178 57.5 59.75 2.25
002131.SZ 利欧股份 2.28 10.14492754 互联网服务 56.75 今日首板 13:00:06 51444872 117294308.2 12.5194 513713638 59.75 56.75 -3
002131.SZ 利欧股份 2.98 9.963099631 互联网服务 75.25 4天2板 9:55:42 90099727 268497186.5 19.2731 7402240 56.75 75.25 18.5
002131.SZ 利欧股份 3.04 10.14492754 互联网服务 77.25 6天3板 10:39:45 82608443 251129666.7 25.218 342502784 75.25 77.25 2
002131.SZ 利欧股份 3.34 9.868421053 互联网服务 77.25 10天5板 10:26:15 65025656 217185691 30.0933 289698176 77.25 77.25 0
002131.SZ 利欧股份 3.67 9.880239521 互联网服务 77.25 11天6板 9:25:00 279918300 1027300161 3.1345 131345890 77.25 77.25 0
002131.SZ 利欧股份 4.04 10.08174387 互联网服务 78 12天7板 9:25:00 449606666 1816410931 0.5042 51532260 77.25 78 0.75
002131.SZ 利欧股份 4.44 9.900990099 互联网服务 78 13天8板 15:00:00 105288354 467480291.8 24.7482 -1271349616 78 78 0
002131.SZ 利欧股份 4.88 9.90990991 互联网服务 80 14天9板 14:54:48 150846812 736132442.6 51.0224 -1702980960 78 80 2
002131.SZ 利欧股份 5.37 10.04098361 互联网服务 78.75 15天10板 10:18:36 130724428 701990178.4 25.5053 478307360 80 78.75 -1.25
证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差
下面是经过进一步优化和调整的完整代码版本,针对您提出的问题做了以下改善:
首行添加完整表头:输出文件的第一行一定会是完整的表头行。
日期格式处理:
dd/mm/yyyy
,无法解析的日期以空白表示,您可以根据需要更改此策略。数据完整性:
分隔行处理:
额外空行(再次分明显示):
在每个股票代码的数据块后面添加一行空行并再次输出表头,以便在多个股票之间有明显的分隔。如果不需要在最后一组后面出现表头,请在最后一组输出数据后不再输出。
根据您的描述,假设您希望在每个股票代码的数据块结束后加一个空行和表头行,以分隔下一个股票数据块。如果您不希望在最后一组数据后重复表头,可以根据判断是最后一个分组来跳过最后的表头。
请根据需要适当微调本代码中注释的逻辑。
pythonimport pandas as pd import os import re from io import StringIO def determine_suffix(stock_code): """ 根据股票代码确定后缀。 以'6'开头的代码添加'.SH',其他的添加'.SZ'。 """ if stock_code.startswith('6'): return '.SH' else: return '.SZ' def process_stock_codes(input_codes): """ 处理输入的股票代码,确保它们具有正确的后缀。 """ processed_codes = [] for code in input_codes: # 去除空白、换行和逗号,并转换为大写 code = code.strip().upper().replace(',', '').replace('\n', '').replace('\r', '') if not code: continue # 跳过空字符串 if '.' in code: # 确保后缀为.SH或.SZ parts = code.split('.') if len(parts) != 2 or parts[1] not in ['SH', 'SZ']: print(f"股票代码 {code} 的后缀无效。跳过。") continue processed_codes.append(code) else: suffix = determine_suffix(code) full_code = f"{code}{suffix}" processed_codes.append(full_code) return processed_codes def main(): # 步骤1:读取输入CSV文件(请根据实际路径修改) input_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\openai-东方 - 涨停池20231214.csv" if not os.path.exists(input_csv_path): print(f"未找到输入CSV文件:{input_csv_path}") return try: with open(input_csv_path, 'r', encoding='gbk') as f: lines = f.readlines() # 过滤掉以“日期:”开头的行和空行 data_lines = [] header_line = None header_set = False # 使用逗号分隔符匹配表头行 header_line_pattern = re.compile(r'^日期,证券代码') for line in lines: if line.startswith('日期:'): # 跳过以"日期:"开头的注释行 continue if line.strip() == '': # 跳过空行 continue if header_line_pattern.match(line): # 如果匹配到表头行且还未设置表头,则保留该行为真正表头行 if not header_set: header_line = line.strip() header_set = True else: # 已有表头则跳过后面的表头行 continue else: data_lines.append(line) if not header_set or header_line is None: print("未找到有效的表头信息。请检查CSV文件格式。") return # 将过滤后的数据行合并为一个字符串 data_str = ''.join(data_lines) # 使用StringIO读取过滤后的数据,并使用逗号作为分隔符 df = pd.read_csv(StringIO(data_str), sep=',', encoding='gbk', dayfirst=True) # 清理列名:去除前后空格并转换为大写 df.columns = df.columns.str.strip().str.upper() # 检查是否存在“证券代码”列 if '证券代码' not in df.columns: print("CSV文件中不包含 '证券代码' 列。请检查列名是否正确。") print("当前列名:", df.columns.tolist()) return # 原始日期列备用 original_dates = df['日期'].astype(str).copy() # 尝试解析日期 df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') # 检查是否有未解析的日期 if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") invalid_dates = original_dates[df['日期'].isnull()].unique() print("无法解析的日期值:", invalid_dates) # 确保“涨停基因”列为数值类型,处理非数值数据 df['涨停基因'] = pd.to_numeric(df['涨停基因'], errors='coerce').fillna(0) # 调试打印数据预览 print("清理后的列名:", df.columns.tolist()) print("数据预览(前5行):") print(df.head()) except Exception as e: print(f"读取输入CSV文件时出错:{e}") return # 步骤2:获取用户输入的股票代码(支持多行输入) print("\n请输入一个或多个股票代码,使用逗号、空格或换行符分隔。") print("输入完成后请按回车换行,再按一次回车结束输入。") print("示例:") print(" - 单行:603278.SH 或 603278,300220,002086.SZ") print(" - 多行:可多行输入代码,每行一个或多个代码,完成后输入空行结束。") # 读取多行输入,直到用户输入空行 input_lines = [] while True: try: line = input() if line.strip() == '': break input_lines.append(line) except EOFError: break # 将多行输入合并为一个字符串 user_input = ' '.join(input_lines) # 使用正则表达式分割输入,支持逗号、空格和换行符 input_codes = re.split(r'[,\s]+', user_input) # 处理股票代码,确保格式正确 stock_codes = process_stock_codes(input_codes) # 调试信息:打印拆分后的代码列表和处理后的股票代码列表 print("\n拆分后的代码列表:", input_codes) print("处理后的股票代码列表:", stock_codes) if not stock_codes: print("未输入有效的股票代码。退出。") return print(f"\n处理后的股票代码:{stock_codes}") # 确保“证券代码”列为字符串类型并转换为大写 df['证券代码'] = df['证券代码'].astype(str).str.upper() # 步骤3:根据股票代码过滤数据 filtered_data = df[df['证券代码'].isin(stock_codes)].copy() if filtered_data.empty: print("未找到输入股票代码的相关数据。") return # 按证券代码和日期排序 filtered_data = filtered_data.sort_values(by=['证券代码', '日期']) # 步骤4:添加前交易日涨停基因、当日交易日涨停基因和涨停基因差 filtered_data['前交易日涨停基因'] = filtered_data.groupby('证券代码')['涨停基因'].shift(1).fillna(0) filtered_data['当日交易日涨停基因'] = filtered_data['涨停基因'] filtered_data['涨停基因差'] = filtered_data['当日交易日涨停基因'] - filtered_data['前交易日涨停基因'] # 确保所有新列为数值类型 filtered_data['前交易日涨停基因'] = pd.to_numeric(filtered_data['前交易日涨停基因'], errors='coerce').fillna(0) filtered_data['当日交易日涨停基因'] = pd.to_numeric(filtered_data['当日交易日涨停基因'], errors='coerce').fillna(0) filtered_data['涨停基因差'] = pd.to_numeric(filtered_data['涨停基因差'], errors='coerce').fillna(0) # Reorder columns as per user requirement desired_columns = [ '日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入', '前交易日涨停基因', '当日交易日涨停基因', '涨停基因差' ] # 检查是否存在所有需要的列并补齐 for col in desired_columns: if col not in filtered_data.columns: filtered_data[col] = pd.NA output_data = filtered_data[desired_columns] # 将日期列格式化为dd/mm/yyyy,如果无法解析则为空 # 为确保每行输出一致性,对NaN填空串 output_data['日期'] = pd.to_datetime(output_data['日期'], errors='coerce').dt.strftime('%d/%m/%Y') output_data = output_data.fillna('') # 步骤5:数据分组、输出到字符串列表 grouped = output_data.groupby('证券代码') stock_codes_list = list(grouped.groups.keys()) num_groups = len(stock_codes_list) # 准备输出行列表 output_lines = [] header_str = '\t'.join(desired_columns) # 第一个输出行是表头 output_lines.append(header_str) # 遍历每个分组的数据 for i, code in enumerate(stock_codes_list): group = grouped.get_group(code) # 输出该组数据行 for idx, row in group.iterrows(): row_values = [str(row[col]) for col in desired_columns] output_lines.append('\t'.join(row_values)) # 如果不是最后一组,在该组后面加一行空行和一行表头作为分隔 if i < num_groups - 1: # 空行 output_lines.append('') # 再次输出表头行 output_lines.append(header_str) # 步骤6:将数据输出到CSV文件 output_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv" try: # 确保输出目录存在 os.makedirs(os.path.dirname(output_csv_path), exist_ok=True) # 写入数据到CSV文件(使用gbk编码) with open(output_csv_path, 'w', encoding='gbk', newline='') as f: for line in output_lines: f.write(line + '\n') print(f"\n数据已成功写入:{output_csv_path}") except Exception as e: print(f"写入输出CSV文件时出错:{e}") if __name__ == "__main__": main()
dd/mm/yyyy
,无法解析的日期将显示为空白字符串。\t
制表符分隔,缺失值填充为空字符串,确保每行的数据列数与表头列数一致。请您根据实际情况调整日期解析和输出格式。如果仍存在问题,请提供具体示例数据和期望的最终输出格式,以便进一步优化。
C:\Users\minus\anaconda3\envs\PY310\python.exe "C:/Users/minus/Desktop/crawl_stock_date/OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.py"
CSV文件中不包含 '证券代码' 列。请检查列名是否正确。
当前列名: ['17/8/2022', '002272.SZ', '川润股份', '10.2', '10.03236246', '工程机械', '88', '10天6板', '9:30:00', '16452837', '167818937.4', '10.7051', '58220233']
Process finished with exit code 0
非常抱歉您在运行脚本时遇到了这些问题。根据您的反馈,主要存在以下几个问题:
这些问题主要源于以下几点:
为了彻底解决这些问题,我对您的脚本进行了以下优化和调整:
改进表头识别:
确保日期正确解析:
dd/mm/yyyy
,无法解析的日期则为空白。保证数据完整性:
优化分隔行的插入逻辑:
以下是经过优化后的完整代码:
pythonimport pandas as pd import os import re from io import StringIO def determine_suffix(stock_code): """ 根据股票代码确定后缀。 以'6'开头的代码添加'.SH',其他的添加'.SZ'。 """ if stock_code.startswith('6'): return '.SH' else: return '.SZ' def process_stock_codes(input_codes): """ 处理输入的股票代码,确保它们具有正确的后缀。 """ processed_codes = [] for code in input_codes: # 去除空白、换行和逗号,并转换为大写 code = code.strip().upper().replace(',', '').replace('\n', '').replace('\r', '') if not code: continue # 跳过空字符串 if '.' in code: # 确保后缀为.SH或.SZ parts = code.split('.') if len(parts) != 2 or parts[1] not in ['SH', 'SZ']: print(f"股票代码 {code} 的后缀无效。跳过。") continue processed_codes.append(code) else: suffix = determine_suffix(code) full_code = f"{code}{suffix}" processed_codes.append(full_code) return processed_codes def main(): # 步骤1:读取输入CSV文件(请根据实际路径修改) input_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\openai-东方 - 涨停池20231214.csv" if not os.path.exists(input_csv_path): print(f"未找到输入CSV文件:{input_csv_path}") return try: with open(input_csv_path, 'r', encoding='gbk') as f: lines = f.readlines() # 过滤掉以“日期:”开头的行和空行 data_lines = [] header_line = None header_set = False # 使用逗号分隔符匹配表头行 header_line_pattern = re.compile(r'^日期\s*,\s*证券代码') for line in lines: if line.startswith('日期:'): # 跳过以"日期:"开头的注释行 continue if line.strip() == '': # 跳过空行 continue if header_line_pattern.search(line): # 如果匹配到表头行且还未设置表头,则保留该行为真正表头行 if not header_set: header_line = line.strip() header_set = True else: # 已有表头则跳过后面的表头行 continue else: data_lines.append(line) if not header_set or header_line is None: print("未找到有效的表头信息。请检查CSV文件格式。") return # 将过滤后的数据行合并为一个字符串 data_str = ''.join(data_lines) # Split header line into columns header_columns = [col.strip() for col in header_line.split(',')] # 使用StringIO读取过滤后的数据,并使用逗号作为分隔符,指定 header=None, names=header_columns df = pd.read_csv(StringIO(data_str), sep=',', encoding='gbk', header=None, names=header_columns, dayfirst=True) # 检查是否存在“证券代码”列 if '证券代码' not in df.columns: print("CSV文件中不包含 '证券代码' 列。请检查列名是否正确。") print("当前列名:", df.columns.tolist()) return # 原始日期列备用 original_dates = df['日期'].astype(str).copy() # 尝试解析日期 df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') # 检查是否有未解析的日期 if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") # 显示无法解析的日期值 invalid_dates = original_dates[df['日期'].isnull()].unique() print("无法解析的日期值:", invalid_dates) # 确保“涨停基因”列为数值类型,处理非数值数据 if '涨停基因' in df.columns: df['涨停基因'] = pd.to_numeric(df['涨停基因'], errors='coerce').fillna(0) else: print("警告:'涨停基因' 列不存在,将填充为0。") df['涨停基因'] = 0 # 调试打印数据预览 print("清理后的列名:", df.columns.tolist()) print("数据预览(前5行):") print(df.head()) except Exception as e: print(f"读取输入CSV文件时出错:{e}") return # 步骤2:获取用户输入的股票代码(支持多行输入) print("\n请输入一个或多个股票代码,使用逗号、空格或换行符分隔。") print("输入完成后请按回车换行,再按一次回车结束输入。") print("示例:") print(" - 单行:603278.SH 或 603278,300220,002086.SZ") print(" - 多行:可多行输入代码,每行一个或多个代码,完成后输入空行结束。") # 读取多行输入,直到用户输入空行 input_lines = [] while True: try: line = input() if line.strip() == '': break input_lines.append(line) except EOFError: break # 将多行输入合并为一个字符串 user_input = ' '.join(input_lines) # 使用正则表达式分割输入,支持逗号、空格和换行符 input_codes = re.split(r'[,\s]+', user_input) # 处理股票代码,确保格式正确 stock_codes = process_stock_codes(input_codes) # 调试信息:打印拆分后的代码列表和处理后的股票代码列表 print("\n拆分后的代码列表:", input_codes) print("处理后的股票代码列表:", stock_codes) if not stock_codes: print("未输入有效的股票代码。退出。") return print(f"\n处理后的股票代码:{stock_codes}") # 确保“证券代码”列为字符串类型并转换为大写 df['证券代码'] = df['证券代码'].astype(str).str.upper() # 步骤3:根据股票代码过滤数据 filtered_data = df[df['证券代码'].isin(stock_codes)].copy() if filtered_data.empty: print("未找到输入股票代码的相关数据。") return # 按证券代码和日期排序 filtered_data = filtered_data.sort_values(by=['证券代码', '日期']) # 步骤4:添加前交易日涨停基因、当日交易日涨停基因和涨停基因差 filtered_data['前交易日涨停基因'] = filtered_data.groupby('证券代码')['涨停基因'].shift(1).fillna(0) filtered_data['当日交易日涨停基因'] = filtered_data['涨停基因'] filtered_data['涨停基因差'] = filtered_data['当日交易日涨停基因'] - filtered_data['前交易日涨停基因'] # 确保所有新列为数值类型 filtered_data['前交易日涨停基因'] = pd.to_numeric(filtered_data['前交易日涨停基因'], errors='coerce').fillna(0) filtered_data['当日交易日涨停基因'] = pd.to_numeric(filtered_data['当日交易日涨停基因'], errors='coerce').fillna(0) filtered_data['涨停基因差'] = pd.to_numeric(filtered_data['涨停基因差'], errors='coerce').fillna(0) # Reorder columns as per user requirement desired_columns = [ '日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入', '前交易日涨停基因', '当日交易日涨停基因', '涨停基因差' ] # 检查是否存在所有需要的列并补齐 for col in desired_columns: if col not in filtered_data.columns: print(f"警告:缺少列 {col},将填充为空。") filtered_data[col] = '' output_data = filtered_data[desired_columns].copy() # 将日期列格式化为dd/mm/yyyy,如果无法解析则为空 output_data['日期'] = pd.to_datetime(output_data['日期'], errors='coerce').dt.strftime('%d/%m/%Y').fillna('') # 填充缺失值为空字符串 output_data = output_data.fillna('') # 步骤5:数据分组、输出到字符串列表 grouped = output_data.groupby('证券代码') stock_codes_list = list(grouped.groups.keys()) num_groups = len(stock_codes_list) # 准备输出行列表 output_lines = [] header_str = '\t'.join(desired_columns) # 第一个输出行是表头 output_lines.append(header_str) # 遍历每个分组的数据 for i, code in enumerate(stock_codes_list): group = grouped.get_group(code) # 输出该组数据行 for idx, row in group.iterrows(): row_values = [str(row[col]) for col in desired_columns] output_lines.append('\t'.join(row_values)) # 如果不是最后一组,在该组后面加一行空行和一行表头作为分隔 if i < num_groups - 1: # 空行 output_lines.append('') # 再次输出表头行 output_lines.append(header_str) # 步骤6:将数据输出到CSV文件 output_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv" try: # 确保输出目录存在 os.makedirs(os.path.dirname(output_csv_path), exist_ok=True) # 写入数据到CSV文件(使用gbk编码) with open(output_csv_path, 'w', encoding='gbk', newline='') as f: for line in output_lines: f.write(line + '\n') print(f"\n数据已成功写入:{output_csv_path}") except Exception as e: print(f"写入输出CSV文件时出错:{e}") if __name__ == "__main__": main()
改进表头识别:
r'^日期,证券代码'
改为r'^日期\s*,\s*证券代码'
,以允许逗号前后的空格。确保Pandas正确读取表头:
header=None
和names=header_columns
参数,将数据行读取为无表头,并手动指定列名。处理日期解析:
dd/mm/yyyy
,无法解析的日期填充为空字符串。保证数据完整性:
desired_columns
,若某列不存在,则添加该列并填充为空字符串。优化分隔行的插入逻辑:
确保输出文件包含表头:
输出文件的第一行包含完整的表头:
日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差
每个不同证券代码的数据之间插入一个空行和表头行,例如:
text12/6/2024 002031.SZ 巨轮智能 2.44 9.90990991 专用设备 65.75 今日首板 9:40:15 25425900 62039196 3.4382 80873602 0 65.75 0 13/12/2023 002031.SZ 巨轮智能 4.27 10.05154639 专用设备 66.75 今日首板 13:48:33 27951100 119351197 22.1947 574851033 65.75 66.75 1 日期 证券代码 证券简称 最新价 涨幅 板块名称 涨停基因 连板 封板时间 封板数 封板额 换手率 净流入 前交易日涨停基因 当日交易日涨停基因 涨停基因差 10/2/2023 002131.SZ 利欧股份 2.08 10.05291005 互联网服务 58.75 今日首板 13:32:30 26253097 54606441.76 6.8428 226817620 0 58.75 0 17/6/2024 002131.SZ 利欧股份 1.5 10.29411765 互联网服务 59.75 今日首板 14:38:33 14423048 21634572 8.2001 85836178 58.75 59.75 2.25 ...
所有数据行完整且包含所有必要的列,避免出现部分行数据不完整的情况。
验证CSV文件格式:
日期,证券代码,...
,并且列之间使用逗号分隔。如果存在其他分隔符(如制表符),请相应调整脚本中的sep
参数。检查数据中的异常日期:
日志记录:
代码优化:
测试与验证:
通过上述优化,您的脚本应能正确生成包含表头的输出文件,并在不同证券代码的数据之间插入清晰的分隔行,确保数据的完整性和可读性。如果在运行优化后的脚本时仍遇到问题,请提供更多详细的错误信息或示例数据,以便进一步协助您解决问题。
如果您有任何其他问题或需要进一步的帮助,请随时告知!
现在数据保存,只有一列的,没有明显的分隔,处理错了,重新更新,要完整的代码
非常抱歉您在运行脚本时遇到了问题。根据您的反馈,输出文件仅有一列且缺少表头,可能是由于分隔符设置不正确或数据处理过程中存在问题。为了彻底解决这些问题,我将提供一个全面优化的完整代码版本。该代码将确保:
pythonimport pandas as pd import os import re from io import StringIO def determine_suffix(stock_code): """ 根据股票代码确定后缀。 以'6'开头的代码添加'.SH',其他的添加'.SZ'。 """ if stock_code.startswith('6'): return '.SH' else: return '.SZ' def process_stock_codes(input_codes): """ 处理输入的股票代码,确保它们具有正确的后缀。 """ processed_codes = [] for code in input_codes: # 去除空白、换行和逗号,并转换为大写 code = code.strip().upper().replace(',', '').replace('\n', '').replace('\r', '') if not code: continue # 跳过空字符串 if '.' in code: # 确保后缀为.SH或.SZ parts = code.split('.') if len(parts) != 2 or parts[1] not in ['SH', 'SZ']: print(f"股票代码 {code} 的后缀无效。跳过。") continue processed_codes.append(code) else: suffix = determine_suffix(code) full_code = f"{code}{suffix}" processed_codes.append(full_code) return processed_codes def main(): # 步骤1:读取输入CSV文件(请根据实际路径修改) input_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\openai-东方 - 涨停池20231214.csv" if not os.path.exists(input_csv_path): print(f"未找到输入CSV文件:{input_csv_path}") return try: with open(input_csv_path, 'r', encoding='gbk') as f: lines = f.readlines() # 过滤掉以“日期:”开头的行和空行 data_lines = [] header_line = None header_set = False # 使用逗号分隔符匹配表头行,允许逗号前后的空格 header_line_pattern = re.compile(r'^日期\s*,\s*证券代码') for line in lines: if line.startswith('日期:'): # 跳过以"日期:"开头的注释行 continue if line.strip() == '': # 跳过空行 continue if header_line_pattern.search(line): # 如果匹配到表头行且还未设置表头,则保留该行为真正表头行 if not header_set: header_line = line.strip() header_set = True else: # 已有表头则跳过后面的表头行 continue else: data_lines.append(line) if not header_set or header_line is None: print("未找到有效的表头信息。请检查CSV文件格式。") return # 将过滤后的数据行合并为一个字符串 data_str = ''.join(data_lines) # 拆分表头列 header_columns = [col.strip() for col in header_line.split(',')] # 使用StringIO读取过滤后的数据,并使用逗号作为分隔符,指定 header=None, names=header_columns df = pd.read_csv(StringIO(data_str), sep=',', encoding='gbk', header=None, names=header_columns, dayfirst=True) # 检查是否存在“证券代码”列 if '证券代码' not in df.columns: print("CSV文件中不包含 '证券代码' 列。请检查列名是否正确。") print("当前列名:", df.columns.tolist()) return # 原始日期列备用 original_dates = df['日期'].astype(str).copy() # 尝试解析日期 df['日期'] = pd.to_datetime(df['日期'], dayfirst=True, errors='coerce') # 检查是否有未解析的日期 if df['日期'].isnull().any(): print("警告:有些日期未能正确解析。请检查日期格式。") # 显示无法解析的日期值 invalid_dates = original_dates[df['日期'].isnull()].unique() print("无法解析的日期值:", invalid_dates) # 确保“涨停基因”列为数值类型,处理非数值数据 if '涨停基因' in df.columns: df['涨停基因'] = pd.to_numeric(df['涨停基因'], errors='coerce').fillna(0) else: print("警告:'涨停基因' 列不存在,将填充为0。") df['涨停基因'] = 0 # 调试打印数据预览 print("清理后的列名:", df.columns.tolist()) print("数据预览(前5行):") print(df.head()) except Exception as e: print(f"读取输入CSV文件时出错:{e}") return # 步骤2:获取用户输入的股票代码(支持多行输入) print("\n请输入一个或多个股票代码,使用逗号、空格或换行符分隔。") print("输入完成后请按回车换行,再按一次回车结束输入。") print("示例:") print(" - 单行:603278.SH 或 603278,300220,002086.SZ") print(" - 多行:可多行输入代码,每行一个或多个代码,完成后输入空行结束。") # 读取多行输入,直到用户输入空行 input_lines = [] while True: try: line = input() if line.strip() == '': break input_lines.append(line) except EOFError: break # 将多行输入合并为一个字符串 user_input = ' '.join(input_lines) # 使用正则表达式分割输入,支持逗号、空格和换行符 input_codes = re.split(r'[,\s]+', user_input) # 处理股票代码,确保格式正确 stock_codes = process_stock_codes(input_codes) # 调试信息:打印拆分后的代码列表和处理后的股票代码列表 print("\n拆分后的代码列表:", input_codes) print("处理后的股票代码列表:", stock_codes) if not stock_codes: print("未输入有效的股票代码。退出。") return print(f"\n处理后的股票代码:{stock_codes}") # 确保“证券代码”列为字符串类型并转换为大写 df['证券代码'] = df['证券代码'].astype(str).str.upper() # 步骤3:根据股票代码过滤数据 filtered_data = df[df['证券代码'].isin(stock_codes)].copy() if filtered_data.empty: print("未找到输入股票代码的相关数据。") return # 按证券代码和日期排序 filtered_data = filtered_data.sort_values(by=['证券代码', '日期']) # 步骤4:添加前交易日涨停基因、当日交易日涨停基因和涨停基因差 filtered_data['前交易日涨停基因'] = filtered_data.groupby('证券代码')['涨停基因'].shift(1).fillna(0) filtered_data['当日交易日涨停基因'] = filtered_data['涨停基因'] filtered_data['涨停基因差'] = filtered_data['当日交易日涨停基因'] - filtered_data['前交易日涨停基因'] # 确保所有新列为数值类型 filtered_data['前交易日涨停基因'] = pd.to_numeric(filtered_data['前交易日涨停基因'], errors='coerce').fillna(0) filtered_data['当日交易日涨停基因'] = pd.to_numeric(filtered_data['当日交易日涨停基因'], errors='coerce').fillna(0) filtered_data['涨停基因差'] = pd.to_numeric(filtered_data['涨停基因差'], errors='coerce').fillna(0) # Reorder columns as per user requirement desired_columns = [ '日期', '证券代码', '证券简称', '最新价', '涨幅', '板块名称', '涨停基因', '连板', '封板时间', '封板数', '封板额', '换手率', '净流入', '前交易日涨停基因', '当日交易日涨停基因', '涨停基因差' ] # 检查是否存在所有需要的列并补齐 for col in desired_columns: if col not in filtered_data.columns: print(f"警告:缺少列 {col},将填充为空。") filtered_data[col] = '' output_data = filtered_data[desired_columns].copy() # 将日期列格式化为dd/mm/yyyy,如果无法解析则为空 output_data['日期'] = pd.to_datetime(output_data['日期'], errors='coerce').dt.strftime('%d/%m/%Y').fillna('') # 填充缺失值为空字符串 output_data = output_data.fillna('') # 步骤5:数据分组、输出到字符串列表 grouped = output_data.groupby('证券代码') stock_codes_list = list(grouped.groups.keys()) num_groups = len(stock_codes_list) # 准备输出行列表 output_lines = [] header_str = ','.join(desired_columns) # 使用逗号作为分隔符 # 第一个输出行是表头 output_lines.append(header_str) # 遍历每个分组的数据 for i, code in enumerate(stock_codes_list): group = grouped.get_group(code) # 输出该组数据行 for idx, row in group.iterrows(): row_values = [str(row[col]) for col in desired_columns] output_lines.append(','.join(row_values)) # 如果不是最后一组,在该组后面加一行空行和一行表头作为分隔 if i < num_groups - 1: # 空行 output_lines.append('') # 再次输出表头行作为分隔 output_lines.append(header_str) # 步骤6:将数据输出到CSV文件 output_csv_path = r"C:\Users\minus\Desktop\crawl_stock_date\OpenAI 01 - 20241209 当天涨停龙头 自动化 对比 连板 基因.csv" try: # 确保输出目录存在 os.makedirs(os.path.dirname(output_csv_path), exist_ok=True) # 写入数据到CSV文件(使用gbk编码) with open(output_csv_path, 'w', encoding='gbk', newline='') as f: for line in output_lines: f.write(line + '\n') print(f"\n数据已成功写入:{output_csv_path}") except Exception as e: print(f"写入输出CSV文件时出错:{e}") if __name__ == "__main__": main()
读取和过滤输入CSV文件:
数据清洗和处理:
添加新列:
准备输出数据:
插入分隔行:
写入输出CSV文件:
分隔符设置:
\t
),可以将','.join(desired_columns)
和','.join(row_values)
中的逗号改为\t
,并相应调整读取和写入的分隔符参数。数据完整性:
日期格式:
输出文件格式:
假设输入数据如下:
text日期,证券代码,证券简称,最新价,涨幅,板块名称,涨停基因,连板,封板时间,封板数,封板额,换手率,净流入 17/8/2022,002272.SZ,川润股份,10.2,10.03236246,工程机械,88,10天6板,9:30:00,16452837,167818937.4,10.7051,58220233 ...
输出CSV文件将如下所示:
text日期,证券代码,证券简称,最新价,涨幅,板块名称,涨停基因,连板,封板时间,封板数,封板额,换手率,净流入,前交易日涨停基因,当日交易日涨停基因,涨停基因差 17/8/2022,002272.SZ,川润股份,10.2,10.03236246,工程机械,88,10天6板,9:30:00,16452837,167818937.4,10.7051,58220233,,88,0 ... 证券代码,证券简称,最新价,涨幅,板块名称,涨停基因,连板,封板时间,封板数,封板额,换手率,净流入,前交易日涨停基因,当日交易日涨停基因,涨停基因差 ...
验证输入文件:
调试输出:
使用Excel查看:
简化测试:
如果在进一步调试后仍然遇到问题,请提供一个简化的示例CSV文件(去除敏感信息)以及期望的输出格式,以便进行更详细的分析和优化。