fix: 修复历史数据Excel格式兼容问题 + 完善开发文档
核心修复: - lottery.py: load_history_data() 添加多格式Excel检测逻辑 支持 格式A(双行header: 新列名+旧列名) 和 格式B(标准列名) - lottery.py: parse_numbers() 新增拼接字符串(14位无分隔符)直接解析 避免 re.findall 将整个号码串视为单个数字的问题 - app.py: load_history_dataframe() 同步修复多格式兼容逻辑 新增: - docs/开发文档-双色球WebUI-v1.0.md: 完整开发文档 - deploy/backup.sh: 备份脚本 测试结果: - 120条历史数据全部正确解析 - 号码生成API正常工作 - 全部API接口测试通过 Issue: BIZ-75
This commit is contained in:
@@ -109,39 +109,67 @@ def add_record(strategy, num_tickets, filename):
|
||||
HISTORY_COLUMNS = ['开奖时间', '期数', '号码', '开机号', '和值特征', '奇偶比', '大小比', '奇偶形态', '跨度', '其他']
|
||||
|
||||
def load_history_dataframe():
|
||||
"""智能加载历史数据 Excel,兼容新旧两种格式。
|
||||
"""智能加载历史数据 Excel,兼容多种格式。
|
||||
|
||||
新格式 (fetch_data.py 修复后): 第一行是标准列名,数据从第二行开始。
|
||||
旧格式 (修复前): 两行 header,第一行英文列名,第二行中文描述行。
|
||||
|
||||
返回的 DataFrame 统一使用标准列名,数据已跳过所有 header 行。
|
||||
格式A(fetch_data.py 当前输出):
|
||||
Row0=新列名(期号|开奖日期|红球1...|蓝球|特别号)
|
||||
Row1=旧列名(开奖时间|期数|号码|开机号|...)
|
||||
Row2+=实际数据
|
||||
格式B(标准格式):
|
||||
Row0=列名(开奖时间|期数|号码|开机号|...)
|
||||
Row1+=数据
|
||||
"""
|
||||
import pandas as pd
|
||||
df = pd.read_excel(CONFIG['history_file'], header=None)
|
||||
raw_df = pd.read_excel(CONFIG['history_file'], header=None)
|
||||
|
||||
# 检测第一行是否包含标准列名
|
||||
first_row = df.iloc[0].astype(str).tolist()
|
||||
is_standard_header = any(col in first_row for col in ['开奖时间', '期数', '号码'])
|
||||
row0_vals = raw_df.iloc[0].astype(str).tolist() if len(raw_df) > 0 else []
|
||||
row1_vals = raw_df.iloc[1].astype(str).tolist() if len(raw_df) > 1 else []
|
||||
|
||||
if is_standard_header:
|
||||
# 新格式: 第一行是标准列名,直接使用
|
||||
data_df = df.iloc[1:].copy()
|
||||
has_legacy_in_row0 = any(col in row0_vals for col in ['开奖时间', '期数', '号码'])
|
||||
has_legacy_in_row1 = any(col in row1_vals for col in ['开奖时间', '期数', '号码'])
|
||||
has_new_cols_in_row0 = any(col in row0_vals for col in ['期号', '开奖日期', '红球 1'])
|
||||
|
||||
if has_new_cols_in_row0 and has_legacy_in_row1:
|
||||
# 格式A:跳过 Row0(新列名) 和 Row1(旧列名),用旧列名,数据从 Row2 开始
|
||||
data_df = raw_df.iloc[2:].copy()
|
||||
num_cols = min(len(data_df.columns), len(HISTORY_COLUMNS))
|
||||
data_df.columns = HISTORY_COLUMNS[:num_cols] + [f'col_{i}' for i in range(num_cols, len(data_df.columns))]
|
||||
elif has_legacy_in_row0:
|
||||
# 格式B:Row0 就是标准列名
|
||||
data_df = raw_df.iloc[1:].copy()
|
||||
num_cols = min(len(data_df.columns), len(HISTORY_COLUMNS))
|
||||
data_df.columns = HISTORY_COLUMNS[:num_cols] + [f'col_{i}' for i in range(num_cols, len(data_df.columns))]
|
||||
else:
|
||||
# 旧格式: 检查是否有两行 header
|
||||
second_row = df.iloc[1].astype(str).tolist() if len(df) > 1 else []
|
||||
has_second_header = any(col in second_row for col in ['开奖时间', '期数', '号码'])
|
||||
|
||||
if has_second_header:
|
||||
# 两行 header,跳过前两行
|
||||
data_df = df.iloc[2:].copy()
|
||||
# 尝试默认读取
|
||||
df = pd.read_excel(CONFIG['history_file'])
|
||||
if '号码' not in df.columns and any(c in df.columns for c in ['红球 1', '红球1']):
|
||||
# 分列格式,需要构建号码列
|
||||
data_df = df.copy()
|
||||
red_cols = [f'红球 {i}' for i in range(1, 7)]
|
||||
if not all(c in data_df.columns for c in red_cols):
|
||||
red_cols = [f'红球{i}' for i in range(1, 7)]
|
||||
if all(c in data_df.columns for c in red_cols) and '蓝球' in data_df.columns:
|
||||
def build_num(row):
|
||||
parts = []
|
||||
for c in red_cols:
|
||||
val = row.get(c)
|
||||
if pd.isna(val):
|
||||
return None
|
||||
s = str(int(val)) if isinstance(val, (int, float)) else str(val).strip()
|
||||
parts.append(s.zfill(2))
|
||||
blue_val = row.get('蓝球')
|
||||
if pd.isna(blue_val):
|
||||
return None
|
||||
blue_s = str(int(blue_val)) if isinstance(blue_val, (int, float)) else str(blue_val).strip()
|
||||
return ''.join(parts) + blue_s.zfill(2)
|
||||
data_df['号码'] = data_df.apply(build_num, axis=1)
|
||||
else:
|
||||
# 只有一行 header,跳过第一行
|
||||
data_df = df.iloc[1:].copy()
|
||||
data_df = df
|
||||
|
||||
num_cols = min(len(data_df.columns), len(HISTORY_COLUMNS))
|
||||
data_df.columns = HISTORY_COLUMNS[:num_cols] + [f'col_{i}' for i in range(num_cols, len(data_df.columns))]
|
||||
# 如果列名不匹配标准,重命名
|
||||
if not any(c in data_df.columns for c in HISTORY_COLUMNS[:3]):
|
||||
data_df.columns = HISTORY_COLUMNS[:num_cols] + [f'col_{i}' for i in range(num_cols, len(data_df.columns))]
|
||||
|
||||
data_df = data_df.reset_index(drop=True)
|
||||
return data_df
|
||||
|
||||
Reference in New Issue
Block a user