定期抓取网页截图并对比,发现页面变化自动发送告警。适合监控竞品网站、政策更新、价格变动等场景。
你有没有遇到过这种情况:蹲点等一个降价通知,结果被别的渠道先知道了?
或者想监控竞品网站有没有改版、新功能上线,却只能每天手动去点一看?
这种时候,脚本比人眼靠谱。
今天做一个网站变化监控工具。它定期截图,对比前后画面,有变化就推送到你的微信或邮箱。
项目背景
很多场景需要盯住某个网页的变化:
- 竞品网站改版、上新品、调价格
- 政策文件更新、公告发布
- 抢票网站余票变化
- 自己网站的访问异常
手动刷新太累,专业工具又贵。用 Python 搭一个自己的监控器,成本为零。
核心思路很简单:
- 定时访问目标网页
- 截图保存
- 与上次截图对比像素差异
- 有变化就发通知
技术选型
| 组件 | 选型 | 理由 |
|---|---|---|
| 网页截图 | playwright | 支持无头浏览器,渲染完整页面 |
| 图像对比 | Pillow + numpy | 计算像素差异率 |
| 定时任务 | APScheduler | Python 内置调度,灵活 |
| 通知推送 | 微信企业号/邮件 | 可替换任意渠道 |
| 配置管理 | YAML | 简单直观,容易扩展 |
实现步骤
第一步:安装依赖
pip install playwright pillow numpy apscheduler pyyaml
playwright install chromium
第二步创建项目目录:
mkdir -p site_monitor/{screenshots,logs}
touch monitor.py config.yaml
第三步:编写配置文件 config.yaml
# 监控目标列表
targets:
- url: "https://example.com"
name: "示例网站"
interval: 3600 # 每小时检查一次
notify: true # 有变化时通知
- url: "https://competitor.com/pricing"
name: "竞品价格页"
interval: 7200 # 每两小时检查
notify: true
# 通知设置
notification:
type: "wechat" # wechat / email / webhook
wechat:
webhook_url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
email:
smtp_server: "smtp.qq.com"
smtp_port: 465
sender: "your@qq.com"
password: "your_password"
receiver: "target@qq.com"
# 截图配置
screenshot:
width: 1440
height: 900
compare_threshold: 0.05 # 像素差异超过5%才触发告警
第四步:编写核心监控脚本 monitor.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import yaml
import time
from datetime import datetime
from pathlib import Path
from PIL import Image
import numpy as np
from playwright.sync_api import sync_playwright
from apscheduler.schedulers.blocking import BlockingScheduler
import requests
# 加载配置
with open("config.yaml", "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
SCREENSHOT_DIR = Path("screenshots")
SCREENSHOT_DIR.mkdir(exist_ok=True)
def take_screenshot(url, name, width=1440, height=900):
"""抓取网页截图"""
filename = f"{SCREENSHOT_DIR}/{name}_{int(time.time())}.png"
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={"width": width, "height": height})
page.goto(url, wait_until="networkidle")
page.screenshot(path=filename, full_page=True)
browser.close()
return filename
def compare_screenshots(old_path, new_path, threshold=0.05):
"""对比两张截图,返回差异率"""
img1 = np.array(Image.open(old_path).convert("L"))
img2 = np.array(Image.open(new_path).convert("L"))
# 调整尺寸到一致
if img1.shape != img2.shape:
img2 = np.array(Image.fromarray(img2).resize((img1.shape[1], img1.shape[0])))
# 计算像素差异率
diff = np.abs(img1.astype(float) - img2.astype(float)) / 255.0
diff_rate = np.mean(diff)
return diff_rate > threshold, diff_rate
def send_wechat_notification(url, name, diff_rate):
"""发送微信通知"""
webhook = config["notification"]["wechat"]["webhook_url"]
message = f"🔔 网站变化监控\n\n网站:{name}\n链接:{url}\n变化率:{diff_rate:.2%}\n时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
payload = {
"msgtype": "text",
"text": {
"content": message
}
}
requests.post(webhook, json=payload, timeout=10)
print(f"✅ 已发送微信通知:{name}")
def check_site(target):
"""检查单个网站是否有变化"""
name = target["name"]
url = target["url"]
notify = target.get("notify", True)
print(f"\n🔍 正在检查:{name} ({url})")
# 获取最新截图
latest = take_screenshot(url, name,
config["screenshot"]["width"],
config["screenshot"]["height"])
# 找上一次截图
screenshots = sorted(SCREENSHOT_DIR.glob(f"{name}_*.png"))
if len(screenshots) < 2:
print(f" ⏳ 首次监控,已保存截图")
return
old_path = screenshots[-2]
new_path = latest
# 删除旧格式截图(避免混淆)
for s in screenshots[:-2]:
s.unlink()
# 对比
changed, diff_rate = compare_screenshots(old_path, new_path,
config["screenshot"]["compare_threshold"])
if changed:
print(f" ⚠️ 检测到变化!差异率:{diff_rate:.2%}")
if notify:
send_wechat_notification(url, name, diff_rate)
else:
print(f" ✅ 无变化(差异率:{diff_rate:.2%})")
# 清理本次截图(保留最新一份)
latest.unlink(missing_ok=True)
def main():
"""主程序"""
scheduler = BlockingScheduler()
for target in config["targets"]:
scheduler.add_job(
check_site,
"interval",
seconds=target["interval"],
args=[target],
id=target["name"],
misfire_grace_time=60
)
print(f"📌 已添加监控任务:{target['name']} (每{target['interval']}秒)")
print("\n🚀 网站变化监控启动,按 Ctrl+C 退出\n")
try:
scheduler.start()
except KeyboardInterrupt:
print("\n👋 监控已停止")
if __name__ == "__main__":
main()
第五步:运行监控
python monitor.py
启动后,程序会按配置的间隔定期检查所有目标网站。有变化时会输出日志并发送微信通知。
运行效果
📌 已添加监控任务:示例网站 (每3600秒)
📌 已添加监控任务:竞品价格页 (每7200秒)
🚀 网站变化监控启动,按 Ctrl+C 退出
🔍 正在检查:示例网站 (https://example.com)
✅ 无变化(差异率:0.02%)
🔍 正在检查:竞品价格页 (https://competitor.com/pricing)
⚠️ 检测到变化!差异率:12.35%
✅ 已发送微信通知:竞品价格页
微信收到通知:
🔔 网站变化监控
网站:竞品价格页
链接:https://competitor.com/pricing
变化率:12.35%
时间:2026-08-04 10:23:15
优化方向
- 智能对比:目前是全图像素对比,可以加入 OCR 识别文字变化,过滤掉广告位变动等干扰
- 变化区域标注:在截图上高亮显示差异区域,一眼看出改了什么
- 历史记录查询:把每次截图存入数据库,支持按时间轴回溯查看
- 浏览器缓存处理:有些网站会做 A/B 测试,可以加入随机 User-Agent 减少误判
- 多渠道通知:除了微信,还支持邮件、钉钉、飞书、Telegram
- Web 控制面板:做一个简单的 Web 界面,查看历史截图、添加/删除监控目标
总结
这个工具的核心价值在于"被动变主动"。
你不需要每天盯着网页看,脚本替你盯着。有变化了再通知你,效率翻倍。
监控对象越多,脚本越值钱。
现在就去加几个你想盯的网站,看看能发现什么。
这篇文章对你有帮助吗?