diff --git a/data_platform/updater.py b/data_platform/updater.py index 818c9b42..0044a88e 100644 --- a/data_platform/updater.py +++ b/data_platform/updater.py @@ -58,51 +58,40 @@ def get_last_date(code: str, exchange: str) -> str: def fetch_incremental(code: str, start_date: str, end_date: str): - """获取增量数据:先试akshare,失败用腾讯K线""" - # 1. akshare + """获取增量数据:腾讯K线(主源,稳定无代理问题)""" + # 直接用腾讯K线API(akshare有代理问题,作为降级备源) try: - import akshare as ak - df = ak.stock_zh_a_hist( - symbol=code, period="daily", - start_date=start_date.replace("-", ""), - end_date=end_date.replace("-", ""), - adjust="" - ) - if df is not None and not df.empty: - df = df.rename(columns={"日期": "date", "开盘": "open", "收盘": "close", - "最高": "high", "最低": "low", "成交量": "volume", - "成交额": "amount"}) - df["date"] = pd.to_datetime(df["date"]).dt.strftime("%Y-%m-%d") - for c in ["open", "high", "low", "close", "volume", "amount"]: - df[c] = pd.to_numeric(df[c], errors="coerce").fillna(0) - return df[["date", "open", "high", "low", "close", "volume", "amount"]] - except Exception as e: - pass # akshare失败,静默切到腾讯 - - # 2. 腾讯K线API - try: - import urllib.request, json + import urllib.request + import json as _json prefix = 'sh' if code.startswith(('6', '5', '1')) else 'sz' tq = f"{prefix}{code}" days = (pd.Timestamp(end_date) - pd.Timestamp(start_date)).days + 10 url = f"https://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param={tq},day,,{days}," # 用无代理opener避免akshare代理污染 - opener = urllib.request.build_opener(urllib.request.ProxyHandler({})) + proxy_handler = urllib.request.ProxyHandler({}) + opener = urllib.request.build_opener(proxy_handler) req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) - with opener.open(req, timeout=10) as r: - data = json.loads(r.read()) - klines = data.get("data", {}).get(tq, {}).get("day", []) + resp = opener.open(req, timeout=10) + raw = resp.read().decode('utf-8', errors='replace') + data = _json.loads(raw) + d = data.get('data') + if not isinstance(d, dict): + return None + klines = d.get(tq, {}).get('day', []) if not klines: return None - df = pd.DataFrame(klines, columns=["date", "open", "close", "high", "low", "volume"]) - for c in ["open", "close", "high", "low", "volume"]: - df[c] = pd.to_numeric(df[c], errors="coerce").fillna(0) - df["amount"] = 0.0 - df["date"] = pd.to_datetime(df["date"]).dt.strftime("%Y-%m-%d") - mask = (df["date"] >= start_date) & (df["date"] <= end_date) - return df.loc[mask, ["date", "open", "high", "low", "close", "volume", "amount"]] + df = pd.DataFrame(klines, columns=['date', 'open', 'close', 'high', 'low', 'volume']) + for c in ['open', 'close', 'high', 'low', 'volume']: + df[c] = pd.to_numeric(df[c], errors='coerce').fillna(0) + df['amount'] = 0.0 + df['date'] = pd.to_datetime(df['date']).dt.strftime('%Y-%m-%d') + mask = (df['date'] >= start_date) & (df['date'] <= end_date) + result = df.loc[mask, ['date', 'open', 'high', 'low', 'close', 'volume', 'amount']] + if result.empty: + return None + return result except Exception as e: - logger.warning(f"腾讯K线也失败 {code}: {e}") + logger.warning(f'腾讯K线失败 {code}: {e}') return None