黑五囤了一堆 VPS 和域名?用 Python 写个到期提醒本,别让续费价偷袭

黑五囤了一堆 VPS 和域名?用 Python 写个到期提醒本,别让续费价偷袭

背景:到期日不是小事,忘一次就够疼

VPS 就是一台租来的远程服务器,按月或按年付费;域名就是网站对外用的地址,同样按年续费。双 11、黑五这种促销季最容易出问题:一个月里连下好几单,首年价便宜、续费价翻倍,到期日又各不相同。忘一次的后果分三档:VPS 过期,上面跑的博客和小服务直接停机;域名过期,网站打不开,严重的还要付赎回费用;自动续费没关,账单按续费价悄悄扣款,月底才发现。

这篇文章不讲怎么抢券,只解决一个很具体的问题:把所有 VPS 和域名的到期日、续费价记在一处,每周自动扫一遍,快到期的提前喊一声。前置知识:会写基础 Python,会用命令行运行 .py 文件,会用 crontab -e 加一条定时任务。文中路径都以 /home/user/ 为例,换成你自己的实际路径。

先定格式:一张 CSV 就是账本

不要一上来就上数据库。一张 CSV 表格够用、能用表格软件打开、丢了也能随手重建。列就四列:名称、类型、到期日、续费价。到期日统一写成 YYYY-MM-DD 这种格式,脚本才能直接算天数;续费价写你账单上的实际价格,买完立刻填,不要凭印象写“大概几十块”。

expiry.csv 的例子(名称和价格均为示例,换成你自己的):

name,type,expiry_date,renewal_price
示例博客域名,域名,2027-01-31,约100元/年
我的大阪 VPS,VPS,2026-11-22,以商家账单为准
备用小鸡,VPS,2026-11-07,以商家账单为准
旧测试域名,域名,2026-10-30,已过期

注意一条红线:这张表只记名称、类型、到期日和价格,不要往里面写密码、密钥、API token,也不要写服务器的真实 IP。账本是用来提醒的,不是用来登录的。

脚本:读表、算天数、分四档

核心逻辑只有三步:读 CSV、算“到期日减今天”的天数、按天数分档。分档定成四档就够了:已过期、7 天内、30 天内、正常。档位太细反而没人看;每周扫一眼,只处理前三档。

把下面这段存为 /home/user/expiry.py,只用 Python 标准库,不装任何依赖:

import csv, sys
from datetime import date


def tier(days):
    if days < 0:
        return "已过期"
    if days <= 7:
        return "7天内"
    if days <= 30:
        return "30天内"
    return "正常"


def main(path):
    today = date.today()
    rows = []
    with open(path, newline="", encoding="utf-8") as f:
        for r in csv.DictReader(f):
            exp = date.fromisoformat(r["expiry_date"])
            days = (exp - today).days
            rows.append((days, r["name"], r["type"], r["expiry_date"],
                         r.get("renewal_price", ""), tier(days)))
    rows.sort()
    print(f"今天:{today}  共 {len(rows)} 条")
    print(f"{'剩余天数':>8}  {'名称':<16} {'类型':<6} {'到期日':<12} {'续费价':<10} 状态")
    for days, name, typ, exp, price, t in rows:
        print(f"{days:>8}  {name:<16} {typ:<6} {exp:<12} {price:<10} {t}")


if __name__ == "__main__":
    main(sys.argv[1])

运行方法:

python3 /home/user/expiry.py /home/user/expiry.csv

用上面那张示例表在本地实测,输出是这样的(日期以实测当天为准):

今天:2026-11-02  共 4 条
    剩余天数  名称               类型     到期日          续费价        状态
      -3  旧测试域名            域名     2026-10-30   已过期        已过期
       5  备用小鸡             VPS    2026-11-07   以商家账单为准    7天内
      20  我的大阪 VPS         VPS    2026-11-22   以商家账单为准    30天内
      90  示例博客域名           域名     2027-01-31   约100元/年    正常

结果按剩余天数从小到大排,最急的永远在最上面,不用逐行翻。负数就是已经过期,别把它当成“还有几天”。

定时:每周跑一次,输出写进日志

提醒脚本最怕两种死法:没人记得跑,或者跑了没人看。把它交给 cron,每周一早上 9 点跑一次,结果追加到日志文件里:

0 9 * * 1 python3 /home/user/expiry.py /home/user/expiry.csv >> /home/user/expiry.log 2>&1

每周一打开日志,只看“已过期、7 天内、30 天内”三档;全是“正常”就直接关掉。定时任务本身也可能挂掉——比如脚本改坏了、文件路径挪了——如果想给它再加一把锁、一个超时和一张心跳,可以看同一系列的定时任务别裸奔:给 cron 加一把锁、一个超时和一张心跳。

三个坑,提前绕开

第一,日期格式别混写。2026/11/22、11-22、2026年11月22日看着都像日期,脚本只认 YYYY-MM-DD,混写会在 fromisoformat 那一步直接报错。宁可建表时多花十秒统一格式,也别在报错时逐行猜。

第二,提前量要留给“处理时间”,不是留给“发现时间”。7 天档的意思是“这周就得决定续不续”,30 天档的意思是“可以比价、可以迁移、可以等下一波促销”。域名尤其别拖到最后一两天:不同注册商的过期处理规则不同,拖过期的代价可能比续费价本身还高,具体以你注册商的规则为准。

第三,续费价字段是这张表的灵魂。只记到期日不记续费价,提醒只能告诉你“快到期了”,不能告诉你“这单续费划不划算”。下单当天就把账单上的续费价抄进来;商家改价、换套餐时同步改一行。买之前先过一遍验货和续费逻辑的,可以对照今天的双11买 VPS 之前,先花 10 分钟过一遍这张验货清单。

顺带一提:运行这类小脚本之前,先确认你本机的 Python 不是太旧的版本。10 月底 Python 全线出过一次紧急安全更新,封堵的是被盗用的证书颁发机构中间证书,Python 官方博客的安全更新公告里列了各分支对应的最新版本号;顺手升到对应分支的最新版,再跑脚本更稳妥。

收尾:一张表、三档提醒,别让续费偷袭

到期提醒不需要做得多花哨:CSV 记四列、脚本分四档、每周跑一次、只看前三档。促销季真正贵的东西从来不是首年价,而是你忘了的那一单续费。到期日和续费价今天花十分钟抄进表里,黑五结束后的每个周一,日志都会替你把最急的那一行顶在最上面。

同系列还可以看:网站巡检那篇网站别等用户来报障:用 Python 写一个 HTTP 与证书到期巡检脚本,证书到期和 VPS、域名到期是同一类问题,巡检脚本和到期提醒本可以共用同一份每周检查习惯。