
为什么需要价格监控
促销季(VPS 行业的黑五、万圣节、双十一都是)有个共同特点:价格和库存一天能变好几次。商家先放出一批特价款,卖完下架;半夜悄悄补货;临近大促又调一波价格。靠人肉刷页面,要么错过、要么把时间全搭进去。
解决办法是写个小脚本替你盯:定时抓取目标页面,提取出价格数字,跟上一次的快照比对,有涨跌就告警。原理只有四步——抓取、提取、比对、通知,全文代码 70 行左右,我在本地真实跑通过,输出原样贴出。
前置知识:会用 pip 装包、知道 cron 是定时任务;Python 3.10 以上。
设计思路
- 抓取:用 requests 把促销页 HTML 拿下来;
- 提取:用正则从 HTML 里抠出价格数字(比如
USD 16.99); - 比对:把每次的价格存进一个 JSON 快照文件,下次运行时对比;
- 告警:降价/涨价打印
[ALERT]行并返回退出码 1,方便定时任务和外部监控对接。
三个细节:目标之间加 1 秒礼貌间隔,别把人家站点当压测靶;正则匹配失败单独报 [WARN](往往是页面改版了);--reset 参数可清空快照重建基线。
环境准备
pip install requests
官方文档:requests 官方文档。
完整代码
把下面代码存为 price_watcher.py,把 TARGETS 换成你真正想盯的促销页 URL 和对应的价格正则:
#!/usr/bin/env python3
"""促销价格变动监控:抓取目标页面 -> 提取价格 -> 与上次快照比对 -> 有变动输出告警。
依赖:pip install requests
用法:python3 price_watcher.py # 正常检查
python3 price_watcher.py --reset # 清空快照重新建基线
退出码:0=正常或首次建基线,1=检测到价格变动
"""
import json, re, sys, time
from pathlib import Path
import requests
# ---------------- 配置区 ----------------
TARGETS = [
# name: 别名; url: 监控的页面; pattern: 提取价格的正则(第一个捕获组为价格)
{"name": "万圣节特价款", "url": "https://example.com/halloween-sale",
"pattern": r"USD\s*([\d.]+)"},
{"name": "闪购专区", "url": "https://example.com/flash-sale",
"pattern": r"\$\s*([\d.]+)"},
]
STATE_FILE = Path("state.json") # 快照存档,跟脚本放同一目录
TIMEOUT = 15 # 单次请求超时(秒)
HEADERS = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) price-watcher/1.0"}
# ----------------------------------------
def fetch_price(t):
r = requests.get(t["url"], headers=HEADERS, timeout=TIMEOUT)
r.raise_for_status()
m = re.search(t["pattern"], r.text)
if not m:
return None, "页面抓到了,但正则没匹配到价格(页面结构可能变了)"
return float(m.group(1)), None
def load_state():
if STATE_FILE.exists():
return json.loads(STATE_FILE.read_text(encoding="utf-8"))
return {}
def main():
if "--reset" in sys.argv and STATE_FILE.exists():
STATE_FILE.unlink()
state = load_state()
changed = False
lines = []
for t in TARGETS:
price, err = fetch_price(t)
if err:
lines.append(f"[WARN] {t['name']}: {err}")
continue
old = state.get(t["name"])
if old is None:
lines.append(f"[INIT] {t['name']}: 首次记录, 基线价格 {price}")
elif abs(price - old) > 1e-9:
arrow = "降价" if price < old else "涨价"
pct = (price - old) / old * 100
lines.append(f"[ALERT] {t['name']}: {arrow}! {old} -> {price} ({pct:+.1f}%)")
changed = True
else:
lines.append(f"[OK] {t['name']}: 无变动 ({price})")
state[t["name"]] = price
time.sleep(1) # 礼貌间隔
STATE_FILE.write_text(json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8")
print("\n".join(lines))
return 1 if changed else 0
if __name__ == "__main__":
sys.exit(main())
真实运行输出
我在本地搭了两个模拟促销页做验证。第一次运行建基线:
[INIT] 示例促销页A: 首次记录, 基线价格 16.99
[INIT] 示例促销页B: 首次记录, 基线价格 49.0
接着把两个页面的价格分别改成降价和涨价,再跑一次:
[ALERT] 示例促销页A: 降价! 16.99 -> 12.99 (-23.5%)
[ALERT] 示例促销页B: 涨价! 49.0 -> 59.0 (+20.4%)
退出码为 1。无变动时输出 [OK]、退出码 0。--reset 可清空快照重新建基线,四条路径全部实测通过。
定时运行:每 30 分钟查一轮
Linux 上用 cron 就够了。crontab -e 加一行:
*/30 * * * * cd /path/to/script && /usr/bin/python3 price_watcher.py >> watcher.log 2>&1
想收到即时提醒,可以把告警行接出去:最省事的是 Telegram Bot API 发一条消息(建个 bot、拿到 token,给自己发 sendMessage 请求只需几行代码);不讲究实时性的话,[ALERT] 行写进日志、每天扫一眼也行。退出码为 1 的设计就是为了方便接 Uptime Kuma 这类外部监控——把它当成一次"检查",非 0 即告警。
同系列:买到机器之后,可以再看一台 VPS 自己管:用 60 行 Python 写个巡检脚本,磁盘内存端口全盯住,把"盯价格"和"盯机器"配成一套。促销季的时间线和避坑点,参考黑五季 VPS 促销全时间线。
三个坑,提前说
- 正则写死价格格式:商家页面一改版,正则就失效——这就是
[WARN]分支存在的意义,收到它先去人工看一眼页面,而不是怀疑脚本坏了。 - 频率别太高:30 分钟一轮足够,促销页不是股票行情;5 分钟一轮容易被当成爬虫封 IP。
- 只盯公开促销页:需要登录、带反爬验证的页面别硬上,换个思路——很多商家有公开的促销 RSS 或邮件订阅,盯那些更稳。
结语
这个脚本的价值不在代码量,而在"把人从刷页面里解放出来"。黑五季真正的好价往往只存活几小时,有个不知疲倦的盯盘员,捡漏概率完全不一样。代码拿去改吧,TARGETS 里换上你自己的目标,今晚就能跑起来。
