這是一個來自真實客戶需求的案例:電商業者每天需要追蹤 5 個競品網站的特定商品定價,過去由業務人員手動查看記錄,費時費力且容易遺漏。我們為他們建立了一套 Python 自動化監控系統,每天定時執行,發現價格異動即透過 LINE 推播通知。
📋 本文技術棧:Python 3.11 / requests / BeautifulSoup4 / pandas / APScheduler / LINE Messaging API
需求分析與架構設計
在動手寫程式前,我們先和客戶確認以下幾點:
- 監控哪些網站?哪些商品頁面?
- 多久執行一次(每天 / 每 6 小時)?
- 價格變動多少才通知(絕對值 or 百分比)?
- 通知發送給哪些人(LINE 群組 / 個人)?
- 歷史資料要不要存(方便繪製趨勢圖)?
確認後,整體架構如下:爬蟲抓取 → 解析比對 → 存入 CSV → 差異通知。
建立基礎爬蟲
安裝必要套件:
pip install requests beautifulsoup4 pandas apscheduler
基礎爬蟲結構:
import requests
from bs4 import BeautifulSoup
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 Chrome/122.0 Safari/537.36'
}
def fetch_price(url: str, selector: str) -> str | None:
"""從指定 URL 抓取價格文字"""
try:
res = requests.get(url, headers=HEADERS, timeout=10)
res.raise_for_status()
soup = BeautifulSoup(res.text, 'html.parser')
el = soup.select_one(selector)
return el.get_text(strip=True) if el else None
except Exception as e:
print(f"[ERROR] {url} → {e}")
return None
⚠️ 注意:部分網站會擋爬蟲,需加入延遲(time.sleep())或使用 rotating proxy。永遠先確認目標網站的 robots.txt 與服務條款。
設定監控目標
將競品清單定義在 JSON 或 Python dict 中,方便日後維護:
TARGETS = [
{
"name": "競品 A — 32吋螢幕",
"url": "https://example-shop-a.com/product/monitor-32",
"selector": ".price-main",
},
{
"name": "競品 B — 32吋螢幕",
"url": "https://example-shop-b.com/items/12345",
"selector": "#pdp-price span",
},
]
比對與存儲歷史紀錄
每次執行時,把新舊價格存到 CSV,方便日後分析趨勢:
import pandas as pd
from datetime import datetime
import os
CSV_FILE = 'price_history.csv'
def save_and_compare(name: str, new_price: str) -> dict:
"""存新資料並回傳是否有變動"""
now = datetime.now().strftime('%Y-%m-%d %H:%M')
row = {'time': now, 'name': name, 'price': new_price}
df_new = pd.DataFrame([row])
if os.path.exists(CSV_FILE):
df = pd.read_csv(CSV_FILE)
# 取上次同商品的最後一筆
prev = df[df['name'] == name].tail(1)
old_price = prev['price'].values[0] if len(prev) else None
changed = (old_price != new_price)
df = pd.concat([df, df_new], ignore_index=True)
else:
df = df_new
old_price = None
changed = False
df.to_csv(CSV_FILE, index=False)
return {'changed': changed, 'old': old_price, 'new': new_price}
LINE 推播通知
價格有變動時,透過 LINE Messaging API 推播給指定用戶或群組:
import requests as req
LINE_TOKEN = 'YOUR_CHANNEL_ACCESS_TOKEN'
LINE_USER_ID = 'Uxxxxxxxxxxxxxxxxx' # 目標用戶的 userId
def notify_line(message: str):
req.post(
'https://api.line.me/v2/bot/message/push',
headers={
'Authorization': f'Bearer {LINE_TOKEN}',
'Content-Type': 'application/json'
},
json={
'to': LINE_USER_ID,
'messages': [{'type': 'text', 'text': message}]
}
)
排程執行(APScheduler)
設定每天早上 9 點自動執行一次:
from apscheduler.schedulers.blocking import BlockingScheduler
def daily_check():
alerts = []
for target in TARGETS:
price = fetch_price(target['url'], target['selector'])
if price:
result = save_and_compare(target['name'], price)
if result['changed']:
alerts.append(
f"⚠️ {target['name']}\n"
f"原價:{result['old']}\n"
f"現價:{result['new']}"
)
if alerts:
notify_line('📊 競品價格異動通知\n\n' + '\n\n'.join(alerts))
else:
print('[OK] 今日無價格變動')
scheduler = BlockingScheduler()
scheduler.add_job(daily_check, 'cron', hour=9, minute=0)
scheduler.start()
實際成效
上線 3 個月後的結果:
- 業務人員每週節省約 3 小時的人工查價時間
- 在競品降價 4 小時內即收到通知,成功搶先應對
- 歷史 CSV 匯入 Google Sheets,形成每月競品分析報表
這套系統可以很容易地擴展:加更多商品、加更多通知管道(Email / Slack)、加入趨勢圖表、或把資料存到 Google Sheets 讓非技術人員查看。如果你有類似需求,歡迎聯繫我們討論。