
开盘前五分钟我还在忙着把昨晚整理好的候选股清单导入脚本今天想做的是在盘中实时盯一下港股的异动。写了个几十行的小工具直接打印腾讯行情接口返回的最新价、涨跌幅、成交量同样时间那些手动刷新网页的同事还在挨个翻行情。这篇博文就是围绕“用 Python 获取实时港股行情数据”这件事从接口选型、环境准备、代码实现到问题排查做一个完整复盘。如果你是个刚接触 Python 的投资者或者想尝试把行情数据接进自己的量化/提醒系统这篇文章会帮你少踩不少坑。腾讯和新浪有公开的港股实时行情接口不需要付费开通数据终端就能拿到分钟级甚至更快的报价而且 Python 处理这类 HTTP 请求 字符串解析非常顺手。我会把背后关于接口字段、请求头、时区判断这些容易被忽略的细节全部展开所有代码都是可以直接复制跑通的。1. 项目背景与方案选型1.1 需求拆解你到底要什么行情很多人一上来就问“怎么获取港股实时行情”但实际场景差别很大。有人只是盯几只看好的股票需要简单的最新价和涨跌幅有人想监控持仓、在个股异动时自动弹窗提醒还有人希望把行情存到数据库里供后续分析。需求不同技术方案的侧重点完全不一样。我自己这次的目标很明确用最小成本拿到港股实时报价包括最新价、今日开盘、最高最低、成交量、成交额、买卖盘口这些基础字段然后做两个应用——一个命令行下实时刷新的迷你看板一个简单的价格波动提醒。这里的关键词是“稳定”和“免费”所以我优先考虑公开 HTTP 接口而不是去向券商申请专门的行情网关。港股实时数据在交易所层面是要收费的但市面上不少门户网站为了展示行情自己购买了数据授权后提供了公开的 HTTP 端口通过模拟浏览器请求就能拿到接近实时的快照。我的方案就是基于这类接口搭建。还要说清楚一个概念实时不等于 tick-by-tick 逐笔成交。对绝大多数个人投资者来说获取到秒级或分钟级的快照已经足够。所谓“实时行情”在免费接口的语境下通常指延迟在几秒到十几秒内的最新报价快照而非 Level-2 的逐笔委托流。如果你的策略真的要求交易所原始行情那就得走正规的行情服务商渠道这不在本文讨论范围。1.2 为什么选择腾讯接口作为主力数据源国内开发者获取港股行情绕不开腾讯和新浪这两个公开接口。我最终选择腾讯接口作为主力原因其实很实在。先说新浪。新浪的hq.sinajs.cn接口返回数据非常简洁一条字符串搞定但有个坑必须带上Referer: https://finance.sina.com.cn这个请求头否则会返回403 Forbidden。腾讯的qt.gtimg.cn接口相对“宽容”一些直接 GET 就能返回而且字段比新浪更丰富包含了多个维度的买卖五档、总市值、市盈率等扩展信息。对于做行情快照和数据解析来说腾讯更顺手。腾讯接口的 URL 格式大概是https://qt.gtimg.cn/qhk00700, hk09988q后面跟股票代码多个代码用英文逗号分隔。港股代码统一使用hk前缀 五位数字。注意腾讯的港股代码一直是五位像腾讯控股是00700不能写成0700或700少了前导零接口会返回空数据。这一点前面调试时踩过坑后面会专门说。返回内容是一段类似v_hk00700200~腾讯控股~00700~...的字符串字段用~分隔。整个响应的处理逻辑非常直接不需要 JSON 解析用split(~)就能把关键字段取出来。对于 Python 这种字符串处理方便的语言来说简直是无脑操作。1.3 数据时效、频率限制和合规边界使用这类免费接口需要先搞清楚它的时效和限制。实测下来腾讯港股接口返回的数据在交易时段内大概是几秒更新一次做日常盯盘完全没问题。但它不是官方交易数据流不要指望它用来做毫秒级的高频策略也不应该把它当成成交量统计的权威来源。关于调用频率这个接口没有明确公布阈值但以我们的经验常规的单机脚本每秒请求一次持续几个小时是没有问题的。如果多人共用同一出口 IP 高频抓取可能会被临时限流表现就是返回空字符串或者v_pv_none_match1。后面第 4 章我会讲遇到限流后怎么处理。合规方面也需要说两句。公开门户接口用于个人学习、研究和非商业用途是行业内大家默认的玩法但如果你想把数据打包出售、提供商业行情服务或者在证券相关业务中作为正式数据源那必须购买授权否则会面临版权和数据服务条款的问题。我的做法是只在个人脚本和自用工具中使用不对外分发原始数据遇到盘口数据只取来辅助判断不做二次传播。这条底线建议读者也守住。2. 开发环境与基础准备2.1 Python 环境安装与依赖库起步阶段假设你的电脑没有 Python。国内用户建议直接到 Python 官网下载对应系统的安装包安装时记得勾选Add Python to PATH否则后面命令行里输入 python 会提示找不到命令。Linux 用户则可以用包管理器安装比如 Ubuntu 上的sudo apt install python3 python3-pip。装好 Python 之后打开终端验证一下python --version如果能正确输出版本号说明环境配置成功。我建议使用 Python 3.8 以上的版本后面代码会用到类型注解和 f-string 等特性太老的版本跑起来会报错。接下来安装第三方库。这个项目实际上只需要一个标准库就可以完成连 requests 都未必用得上因为腾讯接口用urllib.request就能请求。不过为了代码更简洁、处理超时更方便我还是习惯装一下requests。pip install requests如果下载慢把 pip 源切换成国内镜像pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple除了 requests后面做数据可视化的时候还会用到 matplotlib做数据表格处理会用到 pandas。这些可以等实际需要时再装不必一开始就把环境搞得臃肿。我的原则是“用到哪个装哪个”因为每个人扩展的方向不一样。2.2 核心请求头与接口调试技巧腾讯接口虽然不需要 Referer但为了更接近真实浏览器行为建议还是加上User-Agent。有些部署在网络层面做了比较严格的检查伪造一个浏览器的 UA 能减少被拦截的概率。我们先用 curl 或者直接在 Python 里做一个一次性验证看看接口到底返回什么格式。建议刚开始调试时不要批量请求先取一只股票import requests url https://qt.gtimg.cn/qhk00700 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(url, headersheaders, timeout5) resp.encoding gbk # 关键接口返回的是GBK编码 print(resp.text)这里要特别注意resp.encoding gbk。腾讯接口返回的数据是 GBK 编码如果不设置的话requests 大概率会把它识别成 ISO-8859-1中文股票名会直接乱码。这是新手最容易踩的坑之一。运行之后预期会看到类似这样的一长串v_hk00700200~腾讯控股~00700~386.800~386.800~387.200~...;其中以~分隔的每个位置都有固定含义。我的做法是先把它解析成列表然后打印前几个字段对照一下不用硬记序号。如果你对每个字段含义好奇后面第 3 章会给出常见字段对照表。2.3 代码结构规划这个项目虽然小但为了避免逻辑纠缠我建议按功能拆成三个部分数据获取模块负责拼接 URL、发送请求、返回股票代码对应的原始文本。数据解析模块把原始字符串按~拆开转换成字典结构。应用层负责展示、监控或其它业务逻辑。这样做的目的是方便后续扩展。今天你可能只做命令行看板明天想加个网页展示后天想把它接进钉钉/企业微信机器人如果解析层复用得好这些都是改几行代码的事。我们先按照“先跑通、再优化”的思路。第一版可以全部写在一个.py文件里但请在注释里标记清楚边界。这篇文章后面给出的代码都尽量保留这种分层思路让你能直接照着抄。3. 获取行情数据的完整实现3.1 单只股票的实时行情获取先从最简单的开始写一个函数获取单只股票行情并解析成字典。import requests import json def get_quote_hk(symbol: str) - dict: 获取港股实时行情快照 :param symbol: 港股代码如 00700必须带前导零 :return: 解析后的行情字典 # 统一转为标准五位数代码 code fhk{symbol} url fhttps://qt.gtimg.cn/q{code} headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(url, headersheaders, timeout5) resp.encoding gbk text resp.text.strip() if not in text: return {} # 提取等号后面的内容去掉分号和首尾引号 payload text.split(, 1)[1].strip().strip(;).strip() # 按 ~ 拆分字段 fields payload.split(~) # 根据腾讯接口字段顺序组装常用字段 quote { symbol: fields[2] if len(fields) 2 else symbol, name: fields[1] if len(fields) 1 else , price: float(fields[3]) if fields[3] else 0.0, prev_close: float(fields[4]) if fields[4] else 0.0, open: float(fields[5]) if fields[5] else 0.0, volume: int(fields[6]) if fields[6] else 0, high: float(fields[33]) if len(fields) 33 and fields[33] else 0.0, low: float(fields[34]) if len(fields) 34 and fields[34] else 0.0, change: float(fields[31]) if len(fields) 31 and fields[31] else 0.0, change_percent: float(fields[32]) if len(fields) 32 and fields[32] else 0.0, amount: float(fields[37]) if len(fields) 37 and fields[37] else 0.0, } return quote if __name__ __main__: data get_quote_hk(00700) print(json.dumps(data, ensure_asciiFalse, indent2))这段代码有几个地方需要重点说明。第一code fhk{symbol}那里如果传入的是700拼出来就是hk700腾讯接口会找不到股票。所以我建议调用方必须传五位数字。也可以在函数内部强制格式化code fhk{symbol:05}这样即使你传入700它也能自动补全为hk00700。但这个补全逻辑只适用于五位以内的代码如果传入123456就不合适了。实际使用时建议统一在数据源维护五位代码。第二字段位置的编号不是顺序排列的。比如最高价high在fields[33]最低价low在fields[34]涨跌额在fields[31]涨跌幅在fields[32]。这不是我拍脑袋写的而是通过打印完整列表后对应出来的。腾讯接口的字段很丰富但 unfortunately 官方并没有文档明说每个下标含义所以只能靠经验整理。下面我列一下经过多次验证的常用字段对照表。下标含义示例0未知/固定标识2001股票名称腾讯控股2股票代码007003最新价386.8004昨收价386.8005今开价387.2006成交量手123456731涨跌额3.40032涨跌幅0.8833最高价388.40034最低价383.60037成交额元47653212338换手率0.1239市盈率12.34需要说明的是volume在第 6 个字段但腾讯对港股的成交量单位一般是“手”一手可能等于 100 股具体看股票。这个细节我在做成交量对比时专门验证过如果你计算出成交量明显少了一个数量级大概率是单位换算的问题。第三为什么代码里对fields[3]这类位置要做空字符串判断因为当股票代码不存在或者停牌时接口可能返回空字段。如果直接float()会抛异常所以写了个三元表达式判断。实际项目中可以直接封装一个_safe_float函数让代码更整洁def _safe_float(value, default0.0): try: return float(value) except (ValueError, TypeError): return default等到数据源跑起来你会发现安全转换函数几乎是必须的——接口偶尔给你返回--或者空串这都很正常。3.2 批量获取多只股票数据实时盯盘只看一只股票肯定不够更常见的需求是同时监控十几只。腾讯接口支持一次查询多个代码用逗号分隔即可。比如https://qt.gtimg.cn/qhk00700,hk09988,hk03690批量请求的好处很明显减少 HTTP 连接次数速度快很多也能降低被限流的风险。我们把上面的单只代码扩展一下写一个批量函数。import requests def get_quotes_hk(symbols: list) - dict: 批量获取港股行情 :param symbols: 港股代码列表如 [00700, 09988] :return: {symbol: quote_dict} if not symbols: return {} # 统一转为标准五位代码 normalized [] for s in symbols: s s.strip() if not s.isdigit(): raise ValueError(fInvalid symbol: {s}) normalized.append(fhk{s:05}) url https://qt.gtimg.cn/q ,.join(normalized) headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(url, headersheaders, timeout5) resp.encoding gbk result {} # 返回的文本可能有多行每行对应一只股票 for line in resp.text.strip().split(;): line line.strip() if not line: continue if not in line: continue var_part, payload_part line.split(, 1) # 从 v_hk00700 中提取股票代码 var_name var_part.strip() code var_name.replace(v_hk, ).replace(_quote, ).strip() payload payload_part.strip().strip() fields payload.split(~) quote { symbol: code, name: fields[1] if len(fields) 1 else , price: float(fields[3]) if len(fields) 3 and fields[3] else 0.0, prev_close: float(fields[4]) if len(fields) 4 and fields[4] else 0.0, open: float(fields[5]) if len(fields) 5 and fields[5] else 0.0, volume: float(fields[6]) if len(fields) 6 and fields[6] else 0.0, high: float(fields[33]) if len(fields) 33 and fields[33] else 0.0, low: float(fields[34]) if len(fields) 34 and fields[34] else 0.0, change_percent: float(fields[32]) if len(fields) 32 and fields[32] else 0.0, } result[code] quote return result上面这段代码里我用了var_name来提取股票代码。你可能会想为什么不直接从fields[2]取代码确实fields[2]是接口返回的股票代码但它可能包含前导零也可能因为某些股票的特殊代码而不同。从变量名提取会更稳定因为这个变量的格式是腾讯接口固定的就是v_hk加上你请求时的代码。批量请求的一个注意点是返回文本顺序不一定跟请求顺序完全一致。我测试过多次腾讯一般会按请求顺序返回但为了稳妥建议把结果存成字典而不是列表用代码做 key。这样即使顺序有变也不影响使用。3.3 实时报价的数据结构再深入有些读者会问:腾讯接口返回的数据里包含了买卖五档也就是 Level-1 常见的盘口快照。确实虽然腾讯是免费接口但它在某些字段里提供了五档买卖报价。下面是五档对应的下标我列出来作为参考下标含义9买一量手10买一价11买二量12买二价13买三量14买三价15买四量16买四价17买五量18买五价19卖一量20卖一价21卖二量22卖二价23卖三量24卖三价25卖四量26卖四价27卖五量28卖五价如果你要做盘口异动监控可以直接从这些下标取值。不过要记住这里面的量单位同样是“手”别把它当成股。另外港股的价格最小变动单位跟股票价格区间有关比如低价股可能是 0.001高价股可能是 0.2在做价格档位判断时要注意这一点。我实际使用中一般只用到最新价、涨跌幅和成交量盘口数据用得比较少因为免费接口的盘口更新有延迟对手盘判断的参考价值有限。如果你想拿它做盘口深度分析最好跟券商交易软件上的盘口对比一下心里有数再决定是否依赖。3.4 实现一个命令行实时看板光有函数还不够为了实用我写了一个简单的命令行看板可以每隔几秒刷新一次同时展示多只股票。Linux 和 macOS 用的清屏指令是clearWindows 用的是cls代码里做一个跨平台处理。import os import time import requests def get_quotes_hk(symbols): # 这里直接复用上面的批量函数省略重复代码 pass def clear_screen(): os.system(cls if os.name nt else clear) def format_board(symbols): quotes get_quotes_hk(symbols) lines [] header f{代码:8}{名称:10}{最新价:10}{涨跌幅:10}{成交量(手):14} lines.append(header) lines.append(- * len(header)) for sym, q in quotes.items(): name q[name] price q[price] pct q[change_percent] vol q[volume] # 涨跌幅显示带正负号 pct_str f{pct:.2f}% lines.append(f{sym:8}{name:10}{price:10.3f}{pct_str:10}{vol:14,.0f}) return \n.join(lines) if __name__ __main__: watchlist [00700, 09988, 03690, 01810, 02020] while True: clear_screen() print(港股实时行情 - CtrlC 退出) print() try: print(format_board(watchlist)) except Exception as e: print(f获取失败: {e}) # 每5秒刷新一次 time.sleep(5)这段代码的效果是终端会每隔 5 秒刷新一次表格。你可以把它放在桌面角落边做别的事边瞥一眼。如果不想用轮询的方式断点续跑也可以把while True改成循环固定次数或者用计划任务在特定时间段运行。这里有个小技巧刷新频率没必要太激进。免费接口的数据几秒才会更新一次如果你 1 秒刷一次可能看到的价格和上次一样白白消耗请求次数。5 秒是比较合理的间隔。如果你想监控更快的变化可以把高频请求只集中在少数几只有异动的股票上而不是全市场扫描。3.5 将行情数据继续处理画图和存储有时候纯文字不够直观。比如我想看某只股票今天的日内走势但腾讯这个行情接口只返回快照并不包含分时数据。那怎么办一个折中方案是自己定时采集数据把点连成线。虽然不是交易所官方分时但至少能记录我们关注时段的价格变化。我们可以在循环里把每次取到的price和时间戳追加到列表退出时写到 CSV 文件。下面是一个简单示例import csv import time from datetime import datetime # 假设已经定义好 get_quote_hk def collect_to_csv(symbol, duration_seconds3600, interval10): start time.time() rows [] while time.time() - start duration_seconds: q get_quote_hk(symbol) if q: row { ts: datetime.now().isoformat(timespecseconds), price: q[price], volume: q[volume], } rows.append(row) print(row) time.sleep(interval) if rows: with open(f{symbol}_quotes.csv, w, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnames[ts, price, volume]) writer.writeheader() writer.writerows(rows)采集完 CSV 之后用 pandas matplotlib 画图就非常简单了import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(00700_quotes.csv) df[ts] pd.to_datetime(df[ts]) plt.figure(figsize(10, 5)) plt.plot(df[ts], df[price]) plt.title(00700 intraday price snapshot) plt.xlabel(time) plt.ylabel(price) plt.grid(True) plt.show()这种自建数据积累的方式虽然土但对个人研究完全够用。积累几周后你就可以做简单的成交量分布分析或者对比不同股票在同一时段的波动率。当然如果你想要历史全量日线数据分时拼接肯定不行那就需要去拉历史K线接口这是另一个话题了。4. 常见问题与排查技巧实录4.1 返回数据为空或乱码的排查这个是最常见的问题。空数据通常有几个原因一是股票代码格式不对。港股代码必须是五位且带hk前缀。我见过hk0700、700.HK、00700.HK各种写法腾讯接口只认hk00700这一种。建议在代码里做一次严格格式化不接受用户随便输入。二是接口请求失败被限制。你可以先手动在浏览器地址栏访问https://qt.gtimg.cn/qhk00700如果浏览器能正常显示一长串字符说明接口本身没问题那就是脚本里的请求头或者代理设置问题。requests.get可能走了系统代理如果代理不可用就会超时。可以显式设置proxies{}或proxies{http: None, https: None}避免代理干扰。三是编码问题。乱码的根源前面已经说了就是编码没有指定 GBK。有一种更稳妥的写法resp.raw.decode_content True但这不影响文本解码。最直接的办法还是resp.encoding gbk如果你拿到的还是乱码可以打印resp.encoding看看它到底用的什么编码。4.2 请求频率过高被限流的表现和应对如果你写了个 for 循环把几千只股票拆成几百个请求高频循环去抓就可能遇到以下返回内容v_pv_none_match1;或者干脆返回一个空字符串。这就说明你的出口 IP 被临时限制了。遇到这个情况最简单的做法是等下再试同时降低请求频率。更合理的做法是设计重试机制import time def safe_request(url, headers, max_retry3): for i in range(max_retry): try: resp requests.get(url, headersheaders, timeout5) if resp.text.strip(): return resp except requests.RequestException: pass time.sleep(min(2 ** i, 10)) return None指数退避重试是标准做法刚开始失败就等 1 秒再失败等 2 秒、4 秒最多等 10 秒。这样可以避免在服务端还没恢复时持续猛打。另外尽量把多只股票合成一个请求几十上百只也就一个请求搞定自然不会频繁触发限制。4.3 交易时间与时区判断港股交易时间比较特别除了早市、午市还有早盘前的竞价时段。简单判断“现在能不能交易”至少要包含这几种情况周末周六、周日休市。节假日香港公众假期和内地不完全一致比如圣诞节港股休市内地不放假。如果脚本要靠系统日期做判断得维护一个节假日列表或者干脆不判断让脚本一直请求反正接口在休市时返回的也是昨收数据不会报错。盘中港股连续竞价时段是 9:30-12:00、13:00-16:00还有 16:00-16:10 的收市竞价。提前五分钟进场拿到的可能是静默期的快照价格基本不动但这也没问题。在代码里做交易时段判断需要注意时区。如果你的服务器是美国时区或者 UTC直接用datetime.now()判断会出现大偏差。建议强制用香港时区from datetime import datetime, timezone, timedelta hkt timezone(timedelta(hours8)) now_hk datetime.now(hkt)然后把now_hk的小时和分钟拿去判断。我见过有人直接在本地跑结果人在中国时区没问题但部署到云服务器后定时任务全乱套了。统一用timezone(timedelta(hours8))是最稳妥的。4.4 接口偶尔延迟与数据源切换方案腾讯接口虽然总体稳定但也偶尔会出现几秒的延迟某些时候甚至超过 10 秒。这可能是网络链路问题也可能是接口服务繁忙。为了增加可靠性我习惯在代码里留一个“备胎”。新浪接口作为备用请求格式如下https://hq.sinajs.cn/listhf_HK00700注意新浪港股代码格式是hf_HK 五位数字且需要带Referer。如果你已经用了腾讯不一定需要真的切换过去但在设计函数时把数据源抽象出来做成可配置的data_source tencent # 或 sina def get_quote(symbol): if data_source tencent: return get_quote_tencent(symbol) elif data_source sina: return get_quote_sina(symbol)这样一旦腾讯接口暂时不可用手动改一个变量就能切换。我的建议是不要轻易在运行时自动切换因为两个接口字段含义并不完全一致容易产生数据口径混淆。人工切换更安全。另外一个小问题腾讯接口返回的股票名称可能是繁体中文。如果你后续做股票名匹配建议统一转成简体或者直接用代码做 key不要用中文名做唯一标识。4.5 关键细节涨跌幅计算与复权问题腾讯接口直接提供了涨跌幅字段在fields[32]。如果你要用它来判断异动那没问题。但如果你决定自己算用最新价对比昨收价要注意港股可能因拆股、合股、派息导致昨收价出现调整单纯用“现在价格/昨收-1”算出来的涨跌幅跟行情软件显示的不完全一致。所以在绝大多数场景下直接用接口给出的涨跌幅字段更省心它已经处理了权益调整。还有一个细节是浮点精度。港股价格精确到小数点后三位但接口返回的某些字段用了字符串386.800转成float是 386.8展示时想保留三位小数记得用格式化字符串f{price:.3f}。5. 自动化监控与后续扩展建议5.1 如何做一个价格异动提醒行情数据接到手以后最实用的玩法之一就是价格提醒。比如你想在腾讯控股涨幅超过 2% 时收到通知可以写一个简单的轮询脚本。关键不是复杂的算法而是如何合理地触发通知。最简单的方式是启动一个常驻进程每隔 10 秒或 30 秒获取一次行情检查条件满足时推送通知到手机。通知渠道可以使用 Server 酱、钉钉机器人、企业微信机器人、邮件等。这里给一个钉钉机器人的简化示例import requests import time def send_dingtalk(message): webhook https://oapi.dingtalk.com/robot/send?access_tokenYOUR_TOKEN payload { msgtype: text, text: {content: message} } requests.post(webhook, jsonpayload) def monitor(symbol, threshold2.0, interval30): while True: q get_quote_hk(symbol) if q and q[change_percent] threshold: msg f{q[name]}({q[symbol]}) 涨幅 {q[change_percent]:.2f}%现价 {q[price]:.3f} send_dingtalk(msg) # 发送后避免频繁轰炸等到涨幅回调后重新触发 while True: time.sleep(interval) q2 get_quote_hk(symbol) if q2[change_percent] threshold - 0.5: break time.sleep(interval)这里有个很关键的工程细节如果不加“重新触发”逻辑价格只要还在阈值以上脚本就会每 30 秒给你发一条消息非常烦人。我上面的设计是触发后进入“等待”循环直到涨幅回落到阈值以下 0.5 个百分点才解除警报避免重复提醒。你可以根据自己的需要调整回落幅度。5.2 数据落库与基础统计如果你想把行情存储起来做长期分析CSV 是一个起步方案但查询不太方便。更进阶的做法是把数据写入 SQLitePython 内置 sqlite3 模块无需额外安装。我写过一个小例子import sqlite3 from datetime import datetime conn sqlite3.connect(hkoverse.db) conn.execute( CREATE TABLE IF NOT EXISTS quotes ( symbol TEXT, name TEXT, price REAL, change_percent REAL, volume REAL, ts TEXT ) ) def insert_quote(q, tsNone): ts ts or datetime.now().isoformat(timespecseconds) conn.execute(INSERT INTO quotes VALUES (?,?,?,?,?,?), (q[symbol], q[name], q[price], q[change_percent], q[volume], ts)) conn.commit()有了 SQLite 之后你可以按天、按周查询某只股票的价格轨迹也可以结合 Python 的 pandas 做进一步分析。当然长时间高频采集会导致数据库体积膨胀所以建议每隔一段时间清理冗余数据或者按月份分表。个人使用的话SQLite 完全够用不值得为了这个项目专门上 MySQL。5.3 从快照到日线历史数据补全思路有时候我们需要的历史数据不是自己一段段采而是直接拉过去几年的日线。腾讯和新浪也有历史K线的接口但返回格式比较复杂且不是公开文档化的稳定接口。如果你追求稳定且轻量更推荐直接使用一些开源财经数据包比如akshare。akshare封装了大量公开数据源包含港股历史行情接口相对稳定适合个人研究。使用方式很简单import akshare as ak # 获取港股历史日线 df ak.stock_hk_daily(symbol00700, adjustqfq) print(df.tail())不过要提醒一句akshare本质上也是爬取各家网站数据同样存在接口失效的风险。依赖它没问题但版本更新要跟上遇到报错时先升级到最新版本再排查。我在使用中一大半的akshare报错都是因为版本太旧数据源网站调整之后旧版就不兼容了。5.4 把脚本部署到服务器定时运行如果你的电脑不会一直开着可以考虑把采集脚本部署到一台低配置的云服务器或 NAS 上配合 crontab 或 systemd timer 定时跑。部署到 Linux 服务器时建议用venv创建虚拟环境避免污染系统 Python。示例 crontab*/5 9-16 * * 1-5 cd /path/to/project /usr/bin/python3 collector.py logs/collector.log 21上面这个表达式表示周一至周五的 9 点到 16 点之间每 5 分钟执行一次采集脚本。注意这是服务器本地时间如果服务器时区不是东八区要先把 crontab 的时区调整了或者脚本内部自行判断。另一个替代方案是写一个长期运行的 Python 进程配合schedule库做定时任务但 crontab 更简单进程崩了也会被系统自动拉起前提是脚本自身有良好的日志输出。说到日志我强烈建议任何长期运行的脚本都加上日志记录。简单的方式是import logging logging.basicConfig( filenamehquotes.log, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s )这样即使某个时间点数据源异常你也可以事后回溯而不是面对黑屏毫无头绪。6. 复盘与个人经验补充写到这里整个“用 Python 获取实时港股行情数据”的核心内容基本讲完了。最后再分享一段个人体会。我最初做这个项目时注意力全放在“怎么把数据拉下来”但实际过程中花费时间最多的反而是那些看起来微不足道的小问题GBK 编码、前导零、成交量单位、时区、限流重试。如果你也准备自己动手做建议别急着写大段复杂的逻辑先把单只股票的接口跑通把每一行返回内容打印出来看一遍再逐步增加批量、展示和提醒功能。关于数据准确性的问题我必须坦白免费接口的数据偶尔会跟券商软件有细微差异尤其在成交量、盘口这些时变性很强的字段上。所以不要拿它作为交易决策的唯一依据。我自己的习惯是把它用于“发现问题”比如一支股票突然放量大涨脚本提醒我我再打开正式交易软件做二次确认。这种场景下免费接口的性价比已经足够高了。接下来你还可以尝试把行情数据接入 pandas做成策略回测或者用它做同一板块股票的联动分析。思路打开之后这个小小的接口能帮你省下大量手动刷网页的时间。如果你在跑代码时遇到任何跟本文不一致的表现建议先从版本差异和接口变化两个角度排查——这类免费接口没有长期稳定不变的服务保障学会快速适应变化才是长期能用的关键。