Tự build Website Watcher bằng Python: Theo dõi biến động giá và tin tức qua Telegram

Python tutorial - IT technology blog
Python tutorial - IT technology blog

Tại sao bạn nên tự viết công cụ giám sát website?

Mình từng hụt mất chiếc iPhone giảm giá 3 triệu đồng chỉ vì bận họp đúng 15 phút và không kịp F5 trang web. Lúc đó mình mới hiểu cảm giác ngồi canh chừng thủ công giá cả hay tin tức là một việc cực kỳ tốn sức và dễ nản lòng.

Các công cụ như Distill.io hay Visualping khá tốt nhưng bản free thường giới hạn dưới 30 lần check/tháng. Nếu muốn check liên tục mỗi 5 phút, bạn có thể phải chi tới $15 – $25 mỗi tháng. Với Python, bạn có thể tự build một bản clone xịn sò, tùy biến lọc quảng cáo và gửi tin nhắn Telegram hoàn toàn miễn phí.

Nhiều bạn vẫn dùng BeautifulSoup để cào dữ liệu. Tuy nhiên, với các trang web hiện đại dùng React hay Vue, BeautifulSoup thường chỉ trả về một khung HTML trắng trơn. Đó là lý do mình chọn Playwright. Thư viện này giả lập trình duyệt thật, chờ JavaScript render xong mới lấy dữ liệu, giúp xử lý các trang web “khó nhằn” nhất hiện nay.

Chuẩn bị môi trường

Trước tiên, hãy đảm bảo máy bạn đã cài Python 3.8+. Chúng ta sẽ cần Playwright để duyệt web và thư viện requests để kết nối với Telegram API.

# Tạo môi trường ảo để tránh xung đột thư viện
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# Cài đặt Playwright và requests
pip install playwright requests

# Tải trình duyệt Chromium cho Playwright (nặng khoảng 100-150MB)
playwright install chromium

Về phần Telegram, bạn hãy chat với @BotFather, gõ /newbot để lấy API Token. Đừng quên gửi một tin nhắn cho bot rồi truy cập https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates để tìm chat_id của mình nhé.

Triển khai code chi tiết

Script của chúng ta sẽ hoạt động theo mô hình: Truy cập -> Trích xuất -> So sánh -> Thông báo.

1. Lấy dữ liệu với Playwright

Thay vì lấy toàn bộ HTML, bạn nên nhắm thẳng vào một Selector cụ thể (như class giá tiền hoặc id tiêu đề). Cách này giúp tránh tình trạng script báo có thay đổi chỉ vì một cái timestamp hay banner quảng cáo vừa nhảy.

import asyncio
from playwright.async_api import async_playwright

async def get_website_content(url, selector):
    async with async_playwright() as p:
        # Chạy ở chế độ headless (không hiện cửa sổ trình duyệt)
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        
        # Giả lập User-Agent để tránh bị hệ thống anti-bot chặn
        await page.set_extra_http_headers({"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0"})
        
        try:
            await page.goto(url, wait_until="networkidle", timeout=60000)
            await page.wait_for_selector(selector)
            content = await page.inner_text(selector)
            return content.strip()
        except Exception as e:
            print(f"Lỗi truy cập: {e}")
            return None
        finally:
            await browser.close()

2. Kiểm tra thay đổi nội dung

Cách đơn giản nhất để biết có gì mới là lưu kết quả lần chạy trước vào file .txt. Nếu nội dung mới khác nội dung cũ, chúng ta sẽ cập nhật lại file và kích hoạt thông báo.

import os

def has_changed(new_content, filename="last_state.txt"):
    if not os.path.exists(filename):
        with open(filename, "w", encoding="utf-8") as f:
            f.write(new_content)
        return False
    
    with open(filename, "r", encoding="utf-8") as f:
        old_content = f.read()
    
    if new_content != old_content:
        with open(filename, "w", encoding="utf-8") as f:
            f.write(new_content)
        return True
    return False

3. Gửi tin nhắn qua Telegram

Chỉ cần vài dòng code với thư viện requests là bạn đã có thể đẩy thông báo về điện thoại ngay lập tức.

import requests

def notify_telegram(message, token, chat_id):
    url = f"https://api.telegram.org/bot{token}/sendMessage"
    data = {"chat_id": chat_id, "text": message, "parse_mode": "HTML"}
    return requests.post(url, data=data)

Ghép nối các bộ phận

Dưới đây là hàm main để vận hành toàn bộ quy trình. Bạn chỉ cần thay URL và Selector thực tế vào là chạy được ngay.

async def main():
    CONFIG = {
        "url": "https://tiki.vn/dien-thoai-iphone-15-pro-max-p251643444.html",
        "selector": ".price-and-icon",
        "token": "YOUR_TOKEN",
        "chat_id": "YOUR_ID"
    }

    print("Đang kiểm tra website...")
    current_data = await get_website_content(CONFIG["url"], CONFIG["selector"])

    if current_data and has_changed(current_data):
        msg = f"🚀 <b>Cập nhật mới!</b>\nGiá trị: {current_data}\nLink: {CONFIG['url']}"
        notify_telegram(msg, CONFIG["token"], CONFIG["chat_id"])
        print("Đã gửi thông báo!")
    else:
        print("Không có thay đổi nào.")

if __name__ == "__main__":
    asyncio.run(main())

Kinh nghiệm vận hành thực tế

Để script hoạt động ổn định và không bị “bay màu” IP, bạn cần lưu ý 3 điểm sau:

  • Tần suất kiểm tra: Đừng bao giờ check mỗi 1-2 giây. Các site lớn như Shopee hay Amazon sẽ khóa IP bạn ngay. Chu kỳ 15-30 phút là con số hợp lý nhất.
  • Chạy tự động: Nếu có VPS, hãy dùng crontab. Nếu không, hãy tận dụng GitHub Actions để chạy script miễn phí 24/7 mà không cần treo máy cá nhân.
  • Xử lý Dynamic Class: Một số web thay đổi class liên tục sau mỗi lần build. Lúc này, hãy dùng xpath hoặc các thuộc tính cố định như data-testid để định vị phần tử chính xác hơn.

Việc tự tay build một con bot giám sát không chỉ giúp bạn săn được deal hời. Đây còn là cách thực hành tuyệt vời để hiểu về luồng chạy của trình duyệt và cách xử lý dữ liệu thực tế. Chúc các bạn thành công!

Share: