
先说背景:促销季的好价,都是手慢无
每年 10 月到年底是 VPS 促销最密集的时段:万圣节、黑五、圣诞,商家轮番放闪购。今年已经能看到苗头——CloudCone 提前放出了 2026 万圣节促销,最低一款年付 $20.25(2 核 / 1.25GB / 30GB SSD / 4TB 流量,洛杉矶机房);JustHost 的中秋国庆活动全站 6 折,优惠码到 10 月 18 日截止。
这类促销有两个特点:限量(卖完不补)和限时(页面说下架就下架)。人工隔几个小时刷一次页面,既累又容易错过最低点。与其拼手速,不如写个 70 行的 Python 脚本替你 24 小时守着——价格一降到历史最低,Telegram 立刻推送。
前置知识:会装 Python 3,会用 crontab(或 Windows 计划任务 / 群晖计划任务);Telegram 账号一个(没有也能跑,只是通知降级成打印日志)。
原理一句话
定时抓取促销页 → 用正则提取价格数字 → 跟 JSON 文件里的历史快照对比 → 只有"低于历史最低"时才告警 → 推 Telegram。核心就四步,没有魔法。
完整代码:纯标准库,零依赖
#!/usr/bin/env python3
"""price_watch.py — 促销页价格盯盘:跌破历史最低就推 Telegram"""
import json, re, urllib.request, urllib.parse, os
BASE = os.path.dirname(os.path.abspath(__file__))
SNAPSHOT = os.path.join(BASE, 'price_snapshot.json')
# 盯的目标:名字、促销页、抓价格的正则(按页面实际写法调整)
WATCH = [
{
'name': 'CloudCone 万圣节促销',
'url': 'https://www.gwvpsceping.com/20411.html',
'pattern': r'\$([\d.]+)/年',
},
]
TELEGRAM_BOT_TOKEN = '' # 找 @BotFather 建机器人拿到
TELEGRAM_CHAT_ID = '' # 先给机器人发条消息,再调 getUpdates 查
HEADERS = {'User-Agent': 'Mozilla/5.0 (compatible; price-watch/1.0)'}
def fetch(url):
req = urllib.request.Request(url, headers=HEADERS)
with urllib.request.urlopen(req, timeout=20) as r:
charset = r.headers.get_content_charset() or 'utf-8'
return r.read().decode(charset, 'ignore')
def notify(text):
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
print('[notify]', text) # 没配 Telegram 就打印到日志
return
data = urllib.parse.urlencode(
{'chat_id': TELEGRAM_CHAT_ID, 'text': text}).encode()
req = urllib.request.Request(
f'https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage',
data=data, headers=HEADERS)
urllib.request.urlopen(req, timeout=15).read()
def main():
old = json.load(open(SNAPSHOT)) if os.path.exists(SNAPSHOT) else {}
new = dict(old)
for w in WATCH:
try:
prices = re.findall(w['pattern'], fetch(w['url']))
if not prices:
print(f"[{w['name']}] 没抓到价格,检查正则是否匹配页面")
continue
cur = min(float(p) for p in prices)
prev = old.get(w['name'])
print(f"[{w['name']}] 当前最低 ${cur},历史最低 {prev}")
if prev is None or cur < prev:
new[w['name']] = cur
if prev is not None: # 第一次运行只建快照,不告警
notify(f"📉 降价提醒:{w['name']} 从 ${prev}/年 降到 ${cur}/年\n{w['url']}")
except Exception as e:
print(f"[{w['name']}] 抓取失败:{e}")
json.dump(new, open(SNAPSHOT, 'w'), ensure_ascii=False, indent=2)
if __name__ == '__main__':
main()
三处要按自己情况改
- WATCH 列表:把你想盯的促销页加进去。正则怎么写?先
curl下页面源码,看价格在 HTML 里长什么样(比如$20.25/年),再写对应的pattern。一个页面有多个套餐时,正则会抓到一串价格,脚本取最小值——正好对应"最低价款"。 - Telegram 通知:在 Telegram 里搜 @BotFather 建机器人拿到 token;然后给你的机器人发任意一条消息,浏览器打开
https://api.telegram.org/bot<你的token>/getMe同级接口getUpdates查chat.id。填进脚本即可。接口细节见 Telegram Bot API 文档。 - 定时运行:Linux 上加一条 crontab,每 30 分钟跑一次:
*/30 * * * * /usr/bin/python3 /root/scripts/price_watch.py >> /root/scripts/watch.log 2>&1
三个实战坑,提前说
- 别高频抓:30 分钟一轮足够,促销价不会按秒变。频率太高可能被目标站限流,得不偿失。
- JS 渲染的页面抓不到:有些促销页价格是 JS 动态加载的,
urllib拿到的源码里没有价格。这时别硬上无头浏览器——先找找商家有没有官方价格 API 或订阅链接,往往更稳定。 - "涨回去"不打扰你:脚本只在"跌破历史最低"时告警,价格回升或横盘都静默。第一次运行只建立快照基线,不会误报。
下一步
盯到好价、下单之后,别急着部署。建议按这篇的清单先体检:促销季入手 VPS 后,48 小时内要做的 7 项体检——退款期内跑完 CPU、硬盘、线路、IP 七项检查,不合格直接退。
提醒:抓取频率请保持克制,遵守目标网站的服务条款;本文示例价格来自公开促销新闻,下单前以商家页面实时价格为准。
