项目背景
大促来了,你想买的东西降价了吗?盯着页面太累,开价格提醒又要注册平台。自己动手写个比价小助手,自由度最高,想监控什么商品就监控什么。
这个项目用 Python 实现,不需要复杂框架,核心就三件事:定时访问商品页、提取价格、跟目标价比较,触发通知。
技术选型
- Python 3.10+:主语言
- requests + BeautifulSoup4:爬取页面、解析 HTML
- smtplib + email:发邮件通知(用自建邮箱 SMTP)
- schedule:轻量级定时任务库
- SQLite:记录历史价格,方便后续做图表
全程跑在 VPS 上,每天检查两三次,不折腾。
实现步骤
第一步:安装依赖
pip install requests beautifulsoup4 schedule
第二步:写核心代码
创建一个 price_monitor.py:
import requests
import sqlite3
import smtplib
import schedule
import time
from bs4 import BeautifulSoup
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime
import re
# ============ 配置区 ============
# 商品列表:每个商品一个字典
PRODUCTS = [
{
"name": "Sony WH-1000XM5 耳机",
"url": "https://example-product-page-1.com",
"target_price": 1500, # 目标价(元)
"price_css": ".price-class", # 价格元素的 CSS 选择器
},
{
"name": "Kindle Paperwhite 2024",
"url": "https://example-product-page-2.com",
"target_price": 800,
"price_css": "#price-block",
},
]
# 邮件配置
SMTP_HOST = "smtp.qq.com"
SMTP_PORT = 465
EMAIL_USER = "your_email@qq.com"
EMAIL_PASS = "your_smtp_token"
EMAIL_TO = "your_email@qq.com"
# 数据库
DB_PATH = "price_history.db"
# ============ 数据库初始化 ============
def init_db():
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
c.execute("""
CREATE TABLE IF NOT EXISTS prices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_name TEXT,
price REAL,
target_price REAL,
checked_at TEXT
)
""")
conn.commit()
conn.close()
# ============ 价格抓取 ============
def get_price(product):
"""从商品页面抓取当前价格"""
headers = {
"User-Agent": "Mozilla/5.0 (compatible; PriceBot/1.0)"
}
try:
resp = requests.get(product["url"], headers=headers, timeout=10)
resp.encoding = resp.apparent_encoding
soup = BeautifulSoup(resp.text, "html.parser")
# 方式一:CSS 选择器提取
price_elem = soup.select_one(product["price_css"])
if price_elem:
text = price_elem.get_text(strip=True)
# 提取数字
match = re.search(r'[\d,]+\.?\d*', text.replace(",", ""))
if match:
return float(match.group())
# 方式二:如果 CSS 选择器不匹配,尝试通用价格模式
all_prices = soup.find_all(string=re.compile(r'¥?\s*[\d,]+\.?\d*'))
for p in all_prices:
text = p.strip()
match = re.search(r'[\d,]+\.?\d*', text.replace(",", "").replace("¥", ""))
if match:
val = float(match.group())
if 100 < val < 50000: # 过滤掉不合理的小数值
return val
return None
except Exception as e:
print(f" [抓取失败] {product['name']}: {e}")
return None
# ============ 价格记录 ============
def save_price(product_name, price, target_price):
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
c.execute(
"INSERT INTO prices (product_name, price, target_price, checked_at) VALUES (?, ?, ?, ?)",
(product_name, price, target_price, datetime.now().isoformat())
)
conn.commit()
conn.close()
# ============ 邮件通知 ============
def send_notification(product_name, current_price, target_price):
subject = f"🎉 价格触达提醒:{product_name}"
body = f"""
价格触达提醒
商品名称:{product_name}
当前价格:¥{current_price:.2f}
目标价格:¥{target_price:.2f}
当前价格已降至目标价以下,可以入手了!
—— 电商比价小助手
"""
msg = MIMEMultipart()
msg["From"] = EMAIL_USER
msg["To"] = EMAIL_TO
msg["Subject"] = subject
msg.attach(MIMEText(body, "plain", "utf-8"))
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as server:
server.login(EMAIL_USER, EMAIL_PASS)
server.sendmail(EMAIL_USER, EMAIL_TO, msg.as_string())
print(f" [已通知] {product_name}")
# ============ 主检查逻辑 ============
def check_all():
print(f"[{datetime.now().strftime('%H:%M')}] 开始检查...")
for p in PRODUCTS:
price = get_price(p)
if price is None:
print(f" [跳过] {p['name']}:无法获取价格")
continue
save_price(p["name"], price, p["target_price"])
print(f" [{p['name']}] 当前价格: ¥{price:.2f} | 目标价: ¥{p['target_price']:.2f}")
if price <= p["target_price"]:
# 查一下今天是否已经通知过
send_notification(p["name"], price, p["target_price"])
# ============ 定时任务 ============
def main():
init_db()
print("=== 电商比价小助手启动 ===")
schedule.every(6).hours.do(check_all) # 每6小时检查一次
check_all() # 首次立即检查
while True:
schedule.run_pending()
time.sleep(60)
if __name__ == "__main__":
main()
第三步:配置你的商品
修改 PRODUCTS 列表,填入你想监控的商品:
url:商品详情页 URLtarget_price:你期望的价格price_css:页面中显示价格的 CSS 选择器
查 CSS 选择器的方法:在商品页按 F12 打开开发者工具,找到价格数字所在的 HTML 元素,右键 → “Copy selector”。
第四步:设置邮件
将 EMAIL_USER、EMAIL_PASS(SMTP 授权码)、EMAIL_TO 改成你自己的。QQ 邮箱、163 邮箱都支持 SMTP,去邮箱设置里开启 SMTP 服务即可。
第五步:后台运行
nohup python3 price_monitor.py > monitor.log 2>&1 &
或者用 systemd 服务管理(更稳定):
sudo tee /etc/systemd/system/price-monitor.service <<EOF
[Unit]
Description=Price Monitor
After=network.target
[Service]
Type=simple
WorkingDirectory=/home/ubuntu/price-monitor
ExecStart=/usr/bin/python3 /home/ubuntu/price-monitor/price_monitor.py
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable price-monitor
sudo systemctl start price-monitor
运行效果
启动后,程序每 6 小时自动抓取一次价格,记录到 SQLite 数据库。当商品降价到目标价以下时,会自动给你发邮件。
你可以随时查看历史价格:
import sqlite3
conn = sqlite3.connect("price_history.db")
c = conn.cursor()
c.execute("SELECT product_name, price, checked_at FROM prices ORDER BY checked_at DESC LIMIT 20")
for row in c.fetchall():
print(f"{row[0]} | ¥{row[1]:.2f} | {row[2]}")
conn.close()
优化方向
- 添加网页渲染:对于动态加载价格的页面,可以换用 Playwright 替代 requests
- 微信推送:接入 Server酱 或企业微信机器人 webhook,不用查邮箱就能收到提醒
- 价格趋势图:用 Matplotlib 每月自动生成一次价格曲线图
- 多平台对比:同时监控京东、淘宝、拼多多多个平台的价格差异
- 爬虫防封:加代理 IP 池、随机 User-Agent、请求间隔抖动
自己动手搭一个,比开平台的会员提醒实用多了。想监控啥商品?评论区告诉我,我来帮你写选择器。