AutomateMyJob
Back to BlogPython Automation

Build a Price Monitoring Bot with Python: Never Miss a Deal

Alex Rodriguez14 min read

Build a Price Monitoring Bot with Python: Never Miss a Deal

You've had your eye on that new laptop. Or camera. Or gadget. You keep checking the price, hoping it'll drop during a sale. But you can't check every day. And when it does go on sale, you miss it.

Let's build a Python bot that watches prices for you and sends an alert the moment they drop below your target.

What You'll Learn

  • Web scraping for price extraction
  • Storing and comparing price history
  • Sending email and SMS alerts
  • Scheduling automated price checks
  • Handling multiple products and sites

Prerequisites

  • Python 3.8 or higher
  • requests library (pip install requests)
  • BeautifulSoup (pip install beautifulsoup4)
  • Basic understanding of HTML structure

The Problem

Manual price monitoring is tedious:

  • Checking multiple sites daily takes time
  • You forget to check and miss sales
  • Price history disappears when you're not tracking
  • Flash sales happen when you're not looking

The Solution

A Python bot that:

  1. Checks prices automatically on a schedule
  2. Stores price history to track trends
  3. Sends alerts when prices drop
  4. Works across multiple products and sites

Step 1: Basic Price Scraping

First, let's extract a price from a product page:

python
1import requests
2from bs4 import BeautifulSoup
3
4def get_page(url):
5    """
6    Fetch a web page with proper headers.
7    
8    Args:
9        url: The URL to fetch
10    
11    Returns:
12        BeautifulSoup object or None if failed
13    """
14    headers = {
15        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
16        'Accept-Language': 'en-US,en;q=0.9',
17    }
18    
19    try:
20        response = requests.get(url, headers=headers, timeout=15)
21        response.raise_for_status()
22        return BeautifulSoup(response.content, 'html.parser')
23    except requests.RequestException as e:
24        print(f"Error fetching {url}: {e}")
25        return None
26
27
28def extract_price(soup, price_selector):
29    """
30    Extract price from page using CSS selector.
31    
32    Args:
33        soup: BeautifulSoup object
34        price_selector: CSS selector for price element
35    
36    Returns:
37        Float price or None if not found
38    """
39    import re
40    
41    try:
42        price_element = soup.select_one(price_selector)
43        if not price_element:
44            return None
45        
46        price_text = price_element.get_text()
47        
48        # Extract number from price string
49        # Handles: $1,299.99, €99.99, £50.00, etc.
50        match = re.search(r'[\d,]+\.?\d*', price_text.replace(',', ''))
51        if match:
52            return float(match.group().replace(',', ''))
53        
54    except Exception as e:
55        print(f"Error extracting price: {e}")
56    
57    return None
58
59
60# Example usage
61url = "https://example.com/product"
62soup = get_page(url)
63if soup:
64    price = extract_price(soup, ".product-price")
65    print(f"Current price: ${price}")

Step 2: Product Configuration

Define what products to monitor and their price targets:

python
1# products.py - Configuration for products to monitor
2
3PRODUCTS = [
4    {
5        "name": "Sony WH-1000XM5 Headphones",
6        "url": "https://www.amazon.com/dp/B09XS7JWHH",
7        "price_selector": "span.a-price-whole",
8        "target_price": 300.00,
9        "check_enabled": True,
10    },
11    {
12        "name": "MacBook Air M2",
13        "url": "https://www.apple.com/shop/buy-mac/macbook-air",
14        "price_selector": "span.as-price-currentprice",
15        "target_price": 999.00,
16        "check_enabled": True,
17    },
18    {
19        "name": "PS5 Console",
20        "url": "https://www.walmart.com/ip/PlayStation-5/...",
21        "price_selector": "[data-testid='price']",
22        "target_price": 400.00,
23        "check_enabled": True,
24    },
25]

Step 3: Price History Storage

Store prices over time to track trends:

python
1import json
2from datetime import datetime
3from pathlib import Path
4
5
6class PriceHistory:
7    """Store and manage price history."""
8    
9    def __init__(self, history_file="price_history.json"):
10        self.history_file = Path(history_file)
11        self.data = self._load()
12    
13    def _load(self):
14        """Load existing history or create empty."""
15        if self.history_file.exists():
16            with open(self.history_file, 'r') as f:
17                return json.load(f)
18        return {}
19    
20    def _save(self):
21        """Save history to file."""
22        with open(self.history_file, 'w') as f:
23            json.dump(self.data, f, indent=2)
24    
25    def add_price(self, product_name, price):
26        """
27        Add a price point for a product.
28        
29        Args:
30            product_name: Name of the product
31            price: Current price
32        """
33        if product_name not in self.data:
34            self.data[product_name] = {
35                "prices": [],
36                "lowest_price": None,
37                "highest_price": None,
38            }
39        
40        entry = {
41            "price": price,
42            "timestamp": datetime.now().isoformat(),
43        }
44        
45        self.data[product_name]["prices"].append(entry)
46        
47        # Update min/max
48        prices = [p["price"] for p in self.data[product_name]["prices"]]
49        self.data[product_name]["lowest_price"] = min(prices)
50        self.data[product_name]["highest_price"] = max(prices)
51        
52        self._save()
53    
54    def get_lowest_price(self, product_name):
55        """Get the lowest recorded price for a product."""
56        if product_name in self.data:
57            return self.data[product_name].get("lowest_price")
58        return None
59    
60    def get_price_trend(self, product_name, days=7):
61        """
62        Get price trend for last N days.
63        
64        Returns: 'down', 'up', 'stable', or None
65        """
66        if product_name not in self.data:
67            return None
68        
69        prices = self.data[product_name]["prices"]
70        if len(prices) < 2:
71            return None
72        
73        recent = prices[-1]["price"]
74        older = prices[0]["price"]
75        
76        if recent < older * 0.95:  # 5% decrease
77            return "down"
78        elif recent > older * 1.05:  # 5% increase
79            return "up"
80        return "stable"

Step 4: Alert System

Send notifications when prices drop:

python
1import smtplib
2from email.mime.text import MIMEText
3from email.mime.multipart import MIMEMultipart
4
5
6def send_email_alert(product, current_price, target_price, lowest_ever):
7    """
8    Send email alert for price drop.
9    
10    Args:
11        product: Product configuration dictionary
12        current_price: Current price
13        target_price: Target price threshold
14        lowest_ever: Lowest recorded price
15    """
16    sender_email = "your.email@gmail.com"
17    sender_password = "your-app-password"  # Use environment variable!
18    recipient = "your.email@gmail.com"
19    
20    # Determine if this is a new low
21    is_new_low = lowest_ever is None or current_price < lowest_ever
22    
23    subject = f"🔥 Price Alert: {product['name']} - ${current_price:.2f}"
24    
25    body = f"""
26    <html>
27    <body style="font-family: Arial, sans-serif;">
28        <h2>Price Alert!</h2>
29        
30        <h3>{product['name']}</h3>
31        
32        <p style="font-size: 24px; color: #28a745;">
33            Current Price: <strong>${current_price:.2f}</strong>
34        </p>
35        
36        <table style="border-collapse: collapse; margin: 20px 0;">
37            <tr>
38                <td style="padding: 8px; border: 1px solid #ddd;">Target Price:</td>
39                <td style="padding: 8px; border: 1px solid #ddd;">${target_price:.2f}</td>
40            </tr>
41            <tr>
42                <td style="padding: 8px; border: 1px solid #ddd;">Savings:</td>
43                <td style="padding: 8px; border: 1px solid #ddd; color: #28a745;">
44                    ${target_price - current_price:.2f} ({((target_price - current_price) / target_price * 100):.1f}% below target)
45                </td>
46            </tr>
47            {"<tr><td style='padding: 8px; border: 1px solid #ddd;'>🎉</td><td style='padding: 8px; border: 1px solid #ddd; color: #dc3545;'><strong>NEW LOWEST PRICE!</strong></td></tr>" if is_new_low else ""}
48        </table>
49        
50        <p><a href="{product['url']}" style="background-color: #007bff; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px;">View Product</a></p>
51        
52        <hr>
53        <p style="color: #666; font-size: 12px;">
54            Sent by Price Monitor Bot at {datetime.now().strftime('%Y-%m-%d %H:%M')}
55        </p>
56    </body>
57    </html>
58    """
59    
60    msg = MIMEMultipart('alternative')
61    msg['Subject'] = subject
62    msg['From'] = sender_email
63    msg['To'] = recipient
64    msg.attach(MIMEText(body, 'html'))
65    
66    try:
67        with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
68            server.login(sender_email, sender_password)
69            server.send_message(msg)
70        print(f"✅ Alert sent for {product['name']}")
71        return True
72    except Exception as e:
73        print(f"❌ Failed to send alert: {e}")
74        return False

Step 5: The Main Monitor

Bring it all together:

python
1#!/usr/bin/env python3
2"""
3Price Monitor Bot - Track prices and get alerts when they drop.
4Author: Alex Rodriguez
5
6Monitor product prices across multiple websites and receive
7notifications when prices fall below your target.
8"""
9
10import json
11import logging
12import os
13import re
14import smtplib
15import time
16from datetime import datetime
17from email.mime.multipart import MIMEMultipart
18from email.mime.text import MIMEText
19from pathlib import Path
20
21import requests
22from bs4 import BeautifulSoup
23
24
25# ========================================
26# CONFIGURATION
27# ========================================
28
29# Products to monitor
30PRODUCTS = [
31    {
32        "name": "Example Product",
33        "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
34        "price_selector": "p.price_color",
35        "target_price": 50.00,
36        "check_enabled": True,
37    },
38    # Add more products here...
39]
40
41# Alert settings
42EMAIL_ALERTS = True
43EMAIL_ADDRESS = os.environ.get("EMAIL_ADDRESS", "your.email@gmail.com")
44EMAIL_PASSWORD = os.environ.get("EMAIL_PASSWORD", "your-app-password")
45ALERT_RECIPIENT = os.environ.get("ALERT_RECIPIENT", "your.email@gmail.com")
46
47# File paths
48HISTORY_FILE = "price_history.json"
49LOG_FILE = "price_monitor.log"
50
51
52# ========================================
53# LOGGING SETUP
54# ========================================
55
56logging.basicConfig(
57    level=logging.INFO,
58    format='%(asctime)s | %(levelname)-8s | %(message)s',
59    handlers=[
60        logging.FileHandler(LOG_FILE),
61        logging.StreamHandler()
62    ]
63)
64logger = logging.getLogger(__name__)
65
66
67# ========================================
68# PRICE HISTORY MANAGEMENT
69# ========================================
70
71class PriceHistory:
72    """Store and manage price history."""
73    
74    def __init__(self, filepath=HISTORY_FILE):
75        self.filepath = Path(filepath)
76        self.data = self._load()
77    
78    def _load(self):
79        if self.filepath.exists():
80            with open(self.filepath, 'r') as f:
81                return json.load(f)
82        return {}
83    
84    def _save(self):
85        with open(self.filepath, 'w') as f:
86            json.dump(self.data, f, indent=2)
87    
88    def add_price(self, product_name, price, url):
89        if product_name not in self.data:
90            self.data[product_name] = {
91                "url": url,
92                "prices": [],
93                "lowest_price": None,
94                "highest_price": None,
95            }
96        
97        entry = {
98            "price": price,
99            "timestamp": datetime.now().isoformat(),
100        }
101        
102        self.data[product_name]["prices"].append(entry)
103        
104        # Keep only last 100 entries per product
105        if len(self.data[product_name]["prices"]) > 100:
106            self.data[product_name]["prices"] = self.data[product_name]["prices"][-100:]
107        
108        prices = [p["price"] for p in self.data[product_name]["prices"]]
109        self.data[product_name]["lowest_price"] = min(prices)
110        self.data[product_name]["highest_price"] = max(prices)
111        
112        self._save()
113        return self.data[product_name]
114    
115    def get_lowest(self, product_name):
116        if product_name in self.data:
117            return self.data[product_name].get("lowest_price")
118        return None
119    
120    def get_last_price(self, product_name):
121        if product_name in self.data:
122            prices = self.data[product_name].get("prices", [])
123            if len(prices) >= 2:
124                return prices[-2]["price"]
125        return None
126
127
128# ========================================
129# WEB SCRAPING
130# ========================================
131
132def fetch_page(url):
133    """Fetch a web page with proper headers."""
134    headers = {
135        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
136        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
137        'Accept-Language': 'en-US,en;q=0.9',
138        'Accept-Encoding': 'gzip, deflate, br',
139        'Connection': 'keep-alive',
140    }
141    
142    try:
143        response = requests.get(url, headers=headers, timeout=15)
144        response.raise_for_status()
145        return BeautifulSoup(response.content, 'html.parser')
146    except requests.Timeout:
147        logger.error(f"Timeout fetching {url}")
148    except requests.HTTPError as e:
149        logger.error(f"HTTP error {e.response.status_code} for {url}")
150    except requests.RequestException as e:
151        logger.error(f"Error fetching {url}: {e}")
152    
153    return None
154
155
156def extract_price(soup, selector):
157    """Extract price from page using CSS selector."""
158    try:
159        element = soup.select_one(selector)
160        if not element:
161            return None
162        
163        text = element.get_text()
164        
165        # Extract numeric price
166        # Handles various formats: $1,299.99, £50.00, €99,99
167        cleaned = re.sub(r'[^\d.,]', '', text)
168        
169        # Handle European format (comma as decimal)
170        if ',' in cleaned and '.' in cleaned:
171            if cleaned.index('.') < cleaned.index(','):
172                cleaned = cleaned.replace('.', '').replace(',', '.')
173            else:
174                cleaned = cleaned.replace(',', '')
175        elif ',' in cleaned and '.' not in cleaned:
176            # Could be European decimal or thousands separator
177            if len(cleaned.split(',')[-1]) == 2:
178                cleaned = cleaned.replace(',', '.')
179            else:
180                cleaned = cleaned.replace(',', '')
181        
182        return float(cleaned) if cleaned else None
183        
184    except Exception as e:
185        logger.error(f"Error extracting price: {e}")
186    
187    return None
188
189
190def get_title(soup):
191    """Try to extract product title from page."""
192    selectors = ['h1', '.product-title', '.product-name', '#productTitle']
193    
194    for selector in selectors:
195        element = soup.select_one(selector)
196        if element:
197            return element.get_text().strip()[:100]
198    
199    return None
200
201
202# ========================================
203# ALERTS
204# ========================================
205
206def send_email_alert(product, current_price, target_price, lowest_ever, is_new_low):
207    """Send email alert for price drop."""
208    if not EMAIL_ALERTS:
209        return
210    
211    savings = target_price - current_price
212    savings_pct = (savings / target_price) * 100
213    
214    subject = f"🔥 Price Alert: {product['name']} - ${current_price:.2f}"
215    
216    body = f"""
217    <html>
218    <body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
219        <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; text-align: center;">
220            <h1 style="margin: 0;">💰 Price Drop Alert!</h1>
221        </div>
222        
223        <div style="padding: 20px;">
224            <h2>{product['name']}</h2>
225            
226            <div style="background-color: #d4edda; border: 1px solid #c3e6cb; padding: 15px; border-radius: 5px; margin: 20px 0;">
227                <p style="margin: 0; font-size: 28px; color: #155724;">
228                    ${current_price:.2f}
229                </p>
230                <p style="margin: 5px 0 0 0; color: #155724;">
231                    Save ${savings:.2f} ({savings_pct:.1f}% below target!)
232                </p>
233            </div>
234            
235            {"<p style='background-color: #fff3cd; padding: 10px; border-radius: 5px;'>🎉 <strong>NEW ALL-TIME LOW!</strong></p>" if is_new_low else ""}
236            
237            <table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
238                <tr>
239                    <td style="padding: 10px; border-bottom: 1px solid #ddd;">Your Target Price</td>
240                    <td style="padding: 10px; border-bottom: 1px solid #ddd; text-align: right;">${target_price:.2f}</td>
241                </tr>
242                <tr>
243                    <td style="padding: 10px; border-bottom: 1px solid #ddd;">Lowest Recorded</td>
244                    <td style="padding: 10px; border-bottom: 1px solid #ddd; text-align: right;">${lowest_ever:.2f if lowest_ever else 'N/A'}</td>
245                </tr>
246            </table>
247            
248            <p style="text-align: center;">
249                <a href="{product['url']}" style="display: inline-block; background-color: #28a745; color: white; padding: 12px 30px; text-decoration: none; border-radius: 5px; font-weight: bold;">
250                    🛒 Buy Now
251                </a>
252            </p>
253        </div>
254        
255        <div style="background-color: #f8f9fa; padding: 15px; text-align: center; font-size: 12px; color: #666;">
256            Price Monitor Bot • {datetime.now().strftime('%Y-%m-%d %H:%M')}
257        </div>
258    </body>
259    </html>
260    """
261    
262    msg = MIMEMultipart('alternative')
263    msg['Subject'] = subject
264    msg['From'] = EMAIL_ADDRESS
265    msg['To'] = ALERT_RECIPIENT
266    msg.attach(MIMEText(body, 'html'))
267    
268    try:
269        with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
270            server.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
271            server.send_message(msg)
272        logger.info(f"📧 Alert sent for {product['name']}")
273        return True
274    except Exception as e:
275        logger.error(f"Failed to send email: {e}")
276        return False
277
278
279# ========================================
280# MAIN MONITOR
281# ========================================
282
283def check_product(product, history):
284    """
285    Check a single product's price.
286    
287    Returns: Dictionary with check results
288    """
289    logger.info(f"Checking: {product['name']}")
290    
291    result = {
292        "name": product['name'],
293        "url": product['url'],
294        "target_price": product['target_price'],
295        "current_price": None,
296        "status": "unknown",
297        "alert_sent": False,
298    }
299    
300    # Fetch and parse page
301    soup = fetch_page(product['url'])
302    if not soup:
303        result["status"] = "fetch_failed"
304        return result
305    
306    # Extract price
307    price = extract_price(soup, product['price_selector'])
308    if price is None:
309        result["status"] = "price_not_found"
310        logger.warning(f"  Could not extract price for {product['name']}")
311        return result
312    
313    result["current_price"] = price
314    logger.info(f"  Current price: ${price:.2f} (target: ${product['target_price']:.2f})")
315    
316    # Get historical data
317    lowest_ever = history.get_lowest(product['name'])
318    last_price = history.get_last_price(product['name'])
319    
320    # Record this price
321    history.add_price(product['name'], price, product['url'])
322    
323    # Check if this is a new low
324    is_new_low = lowest_ever is None or price < lowest_ever
325    
326    # Determine if we should alert
327    if price <= product['target_price']:
328        result["status"] = "below_target"
329        logger.info(f"  🎯 BELOW TARGET! (${price:.2f} <= ${product['target_price']:.2f})")
330        
331        # Send alert
332        alert_sent = send_email_alert(
333            product, price, product['target_price'], lowest_ever, is_new_low
334        )
335        result["alert_sent"] = alert_sent
336        
337    elif is_new_low:
338        result["status"] = "new_low"
339        logger.info(f"  📉 New lowest price recorded: ${price:.2f}")
340        
341    elif last_price and price < last_price:
342        result["status"] = "price_dropped"
343        logger.info(f"  ↓ Price dropped from ${last_price:.2f}")
344        
345    else:
346        result["status"] = "above_target"
347    
348    return result
349
350
351def run_monitor():
352    """Run the price monitor for all products."""
353    logger.info("=" * 60)
354    logger.info("PRICE MONITOR STARTING")
355    logger.info(f"Time: {datetime.now()}")
356    logger.info(f"Products to check: {len([p for p in PRODUCTS if p['check_enabled']])}")
357    logger.info("=" * 60)
358    
359    history = PriceHistory()
360    results = []
361    
362    for product in PRODUCTS:
363        if not product.get('check_enabled', True):
364            continue
365        
366        result = check_product(product, history)
367        results.append(result)
368        
369        # Be polite - wait between requests
370        time.sleep(2)
371    
372    # Summary
373    logger.info("\n" + "=" * 60)
374    logger.info("SUMMARY")
375    logger.info("=" * 60)
376    
377    alerts_sent = sum(1 for r in results if r['alert_sent'])
378    below_target = sum(1 for r in results if r['status'] == 'below_target')
379    failed = sum(1 for r in results if r['status'] in ['fetch_failed', 'price_not_found'])
380    
381    logger.info(f"Products checked: {len(results)}")
382    logger.info(f"Below target price: {below_target}")
383    logger.info(f"Alerts sent: {alerts_sent}")
384    logger.info(f"Failed checks: {failed}")
385    
386    return results
387
388
389def main():
390    """Main entry point."""
391    try:
392        run_monitor()
393    except KeyboardInterrupt:
394        logger.info("\nMonitor stopped by user")
395    except Exception as e:
396        logger.exception(f"Monitor failed: {e}")
397        raise
398
399
400if __name__ == "__main__":
401    main()

How to Run This Script

  1. Install dependencies:

    bash
    1pip install requests beautifulsoup4
  2. Configure products in the PRODUCTS list:

    • Get the product URL
    • Find the price selector (right-click price → Inspect)
    • Set your target price
  3. Set up email alerts:

    bash
    1export EMAIL_ADDRESS="your.email@gmail.com"
    2export EMAIL_PASSWORD="your-app-password"
    3export ALERT_RECIPIENT="your.email@gmail.com"
  4. Run manually:

    bash
    1python price_monitor.py
  5. Schedule automatic checks (see our scheduling guide):

    bash
    1# Run every 6 hours
    20 */6 * * * /usr/bin/python3 /path/to/price_monitor.py

Finding Price Selectors

  1. Open the product page in your browser
  2. Right-click on the price → Inspect
  3. Look for the HTML element containing the price
  4. Find a unique identifier:
    • Class: .product-price, .a-price-whole
    • ID: #priceblock_ourprice
    • Data attribute: [data-price]
  5. Test in browser console: document.querySelector(".your-selector")

Customization Options

Add Multiple Alert Thresholds

python
1PRODUCTS = [
2    {
3        "name": "Product",
4        "url": "...",
5        "price_selector": "...",
6        "target_price": 100,
7        "alert_thresholds": [
8            {"price": 100, "message": "Good deal!"},
9            {"price": 80, "message": "Great deal!"},
10            {"price": 60, "message": "AMAZING DEAL!"},
11        ],
12    },
13]

Track Price History Graph

python
1import matplotlib.pyplot as plt
2
3def plot_price_history(product_name, history):
4    """Generate price history chart."""
5    data = history.data.get(product_name, {})
6    prices = data.get("prices", [])
7    
8    if not prices:
9        return
10    
11    dates = [p["timestamp"][:10] for p in prices]
12    values = [p["price"] for p in prices]
13    
14    plt.figure(figsize=(10, 5))
15    plt.plot(dates, values, marker='o')
16    plt.title(f"Price History: {product_name}")
17    plt.xlabel("Date")
18    plt.ylabel("Price ($)")
19    plt.xticks(rotation=45)
20    plt.tight_layout()
21    plt.savefig(f"{product_name}_history.png")

Common Issues & Solutions

IssueSolution
Price not foundCheck selector; site may use JavaScript (try Selenium)
Getting blockedAdd delays; rotate User-Agents; use proxies
Wrong price extractedSelector may match multiple elements; be more specific
Email alerts failCheck Gmail app password; verify credentials
Prices in wrong formatAdjust the price parsing regex for your locale

Taking It Further

Add Browser Automation for JavaScript Sites

python
1# pip install selenium webdriver-manager
2from selenium import webdriver
3from selenium.webdriver.chrome.service import Service
4from webdriver_manager.chrome import ChromeDriverManager
5
6def fetch_js_page(url):
7    """Fetch page that requires JavaScript."""
8    options = webdriver.ChromeOptions()
9    options.add_argument('--headless')
10    
11    driver = webdriver.Chrome(
12        service=Service(ChromeDriverManager().install()),
13        options=options
14    )
15    
16    try:
17        driver.get(url)
18        time.sleep(3)  # Wait for JS to load
19        return BeautifulSoup(driver.page_source, 'html.parser')
20    finally:
21        driver.quit()

SMS Alerts via Twilio

python
1# pip install twilio
2from twilio.rest import Client
3
4def send_sms_alert(message):
5    client = Client("ACCOUNT_SID", "AUTH_TOKEN")
6    client.messages.create(
7        body=message,
8        from_="+1234567890",
9        to="+0987654321"
10    )

Conclusion

You now have a complete price monitoring system. It checks prices automatically, stores history for trend analysis, and alerts you the moment prices drop below your targets.

Never miss a deal again. Set your target prices, schedule the script, and let Python do the watching. When that price drops, you'll be the first to know.

Your personal shopping assistant, automated.

Sponsored Content

Interested in advertising? Reach automation professionals through our platform.

Share this article