要稳定运行超一周,必须处理网络超时、API限频、时区错位和浮点精度问题:用系统级调度替代schedule;requests加timeout=5;用data.get("rates", {}).get("USD")校验汇率;存入SQLite并带时区的ISO8601时间;全程用Decimal计算差额。

直接用 schedule + requests 能跑通,但真要稳定运行超过一周,必须处理网络超时、API限频、时区错位和浮点精度这四个问题。
用 schedule 设置定时任务但别信它的“每小时”
schedule 的 every().hour.at(":00") 看似准时,实际依赖 Python 进程不被中断、系统时间不跳变。生产环境更可靠的是用系统级调度(cron 或 Windows Task Scheduler)启动脚本,Python 内部只做单次抓取逻辑。
- 如果非要用
schedule,务必加while True:循环 +time.sleep(1),否则主线程退出后任务就停了 - 避免写
every(60).minutes—— 它从注册时刻开始计时,不是整点对齐,容易漂移 - 测试时用
schedule.run_all()手动触发,别等一小时
调用汇率 API 时必须检查 response.status_code 和 rate 字段是否存在
免费汇率 API(如 exchangerate-api.com v6、fixer.io)返回 200 不代表数据可用:可能返回兜底值(如 {"rate": 1.0}),或字段名突然变更(rates.USD → rates.usd)。
- 不要直接写
data["rates"]["USD"],先用data.get("rates", {}).get("USD") - 加一层校验:若
rate是None、0或float("inf"),跳过本次计算并记录警告 - 推荐加
timeout=5到requests.get(),否则卡死会拖垮整个定时循环
存历史汇率别用 CSV 用 SQLite,且必须带时区信息
CSV 没有类型约束,多次追加后容易出现字符串混入数字、换行符破坏结构;更重要的是,没时区的时间戳(如 "2024-05-20 14:30")在夏令时切换期会导致差额计算错误。
立即学习“Python免费学习笔记(深入)”;
- 建表语句里用
TEXT存 ISO8601 格式时间:"2024-05-20T14:30:00+08:00",Python 用datetime.now().astimezone().isoformat()写入 - 查最近两条记录算差额时,用
ORDER BY timestamp DESC LIMIT 2,别依赖文件末尾行 - SQLite 自带事务,写入失败不会留下半截数据
计算差额时用 decimal.Decimal 而非 float
汇率常有 5 位小数(如 7.79245),float 在反复加减后会产生微小误差(0.1 + 0.2 != 0.3),导致差额判断失准。
- 所有汇率值入库前转成
Decimal("7.79245"),运算全程保持字符串初始化 - 差额阈值比较别写
abs(new - old) > 0.001,改用(new - old).copy_abs() > Decimal("0.001") - 输出给用户看的数值再用
quantize(Decimal("0.00001"))控制小数位,避免7.792449999999999这种显示
真正难的不是抓数据,而是让脚本在没人看管时持续识别“这次拿到的是真数据”——网络抖动、API 变更、系统休眠、磁盘满,每个环节都得留退路。比如写入失败时缓存到内存列表,下次成功再批量 flush,比直接丢弃强。


















