Python Tutorial: How to Build an E-commerce Price Tracker
The process of making a high-value purchase normally involves comparing prices from different sellers. In a situation where you need to purchase a laptop with a budget of under $1000, and you need to track its listing price from 10 different websites, an automated price tracker will really be helpful.
Most Ecommerce websites constantly change product prices for various reasons; flash sales, dynamic pricing, and competitor matching. This might result to missed purchasing opportunities for some consumers.
For brands, tracking competitor prices is a part of the marketing and advertising strategies. But manually checking and rechecking competitor prices is tedious while most “price alert” services are severely limited.
This guide showcases the processes of developing your own unique price tracker from scratch using Python. It also includes reliable development tips such as how to store historical prices, how to scrape data ethically, how to detect drops, and how to initiate email alerts.
Prerequisites
To follow along, you’ll need:
Python 3.10+ installed on your machine
Basic knowledge of Python (functions, classes, lists, dicts, file I/O)
Familiarity with HTML structure (tags, classes, attributes)
A code editor (VS Code, PyCharm, or any)
Pip for installing packages
Even though web scraping is powerful and valuable for most businesses, it should always be done ethically and responsibly. Always:
Check robots.txt (e.g., https://example.com/robots.txt)
Respect rate limits (add delays between requests)
Identify your bot via a custom User-Agent header
Never bypass login or authentication
Parsing HTML with BeautifulSoup
With BeautifulSoup, developers are able to transform a basic HTML structure into one that is easily navigable.
Elements can be found by class, id, tag, or CSS selectors which will come in handy when extracting data such as product name, product price, and availability.
Each price retrieved from a website is stored as a record in a database which allows you do easily identify and monitor pricing trends.
The tracker will be scheduled with cron (Linux/macOS) or Task Scheduler (Windows), or use a Python library like schedule.
For the notification system, we will be using email since it is the simplest and most available alert method. When a target price is hit, Gmail’s server (SMTP) will send email notifications.
Step-by-Step Tutorial: Building the Price Tracker
In this guide, we are building a price tracker that monitors products on a real website (a demo site or a public target like books.toscrape.com for learning. You’ll need to adapt the selector for production.
Step 1: Set Up Your Environment
Start by setting up a virtual environment and new directory:
bash
mkdir price-tracker
cd price-tracker
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
Install required packages:
bash
pip install requests beautifulsoup4 lxml sqlite3 schedule python-dotenv
You don’t have to install sqlite3 as it comes preinstalled with Python.
Step 2: Understand the Target Website Structure
This tutorial uses http://books.toscrape.com/ – a safe, static ecommerce demo site. Open a product page, e.g., http://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html. Inspect the price element (right-click → Inspect). You’ll see:
<p class="price_color">£51.77</p>
We’ll extract that price.
Step 3: Write a Scraper Function
Create scraper.py:
import requests
from bs4 import BeautifulSoup
import re
def get_product_price(url):
"""
Fetch the product page and extract the current price.
Returns a float or None if not found.
"""
headers = {
'User-Agent': 'PriceTrackerBot/1.0 (+https://yourdomain.com/bot)'
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status() # Raise exception for 4xx/5xx
except requests.RequestException as e:
print(f"Error fetching {url}: {e}")
return None
soup = BeautifulSoup(response.text, 'lxml')
# Find the price element – this selector is site-specific
price_element = soup.select_one('p.price_color')
if not price_element:
# Fallback: try searching for any text containing £ or $
price_text = soup.find(string=re.compile(r'£\d+\.\d{2}'))
if price_text:
raw = price_text.strip()
else:
return None
else:
raw = price_element.text.strip()
# Extract number: remove currency symbol and convert to float
price_match = re.search(r'(\d+\.\d{2})', raw.replace(',', ''))
if price_match:
return float(price_match.group(1))
return None
# Test it
if __name__ == '__main__':
test_url = 'http://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html'
price = get_product_price(test_url)
print(f"Current price: £{price}" if price else "Price not found")
Run it: python scraper.py.
You should see Current price: £51.77.
Step 4: Set Up the Database
Each price check is stored in the database with a timestamp.
Create database.py:
import sqlite3
from datetime import datetime
DB_NAME = 'prices.db'
def init_db():
"""Create the price_history table if it doesn't exist."""
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS price_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_url TEXT NOT NULL,
product_name TEXT,
price REAL,
checked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
def save_price(product_url, product_name, price):
"""Insert a new price record."""
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO price_history (product_url, product_name, price, checked_at)
VALUES (?, ?, ?, ?)
''', (product_url, product_name, price, datetime.now()))
conn.commit()
conn.close()
def get_last_price(product_url):
"""Return the most recent price for a product, or None."""
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
cursor.execute('''
SELECT price FROM price_history
WHERE product_url = ?
ORDER BY checked_at DESC LIMIT 1
''', (product_url,))
row = cursor.fetchone()
conn.close()
return row[0] if row else None
Step 5: Add Product Name Extraction
Enhance scraper.py to also get the product title:
def get_product_info(url):
headers = {'User-Agent': 'PriceTrackerBot/1.0'}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'lxml')
# Extract title
title_elem = soup.select_one('h1')
product_name = title_elem.text.strip() if title_elem else "Unknown"
# Extract price
price = None
price_elem = soup.select_one('p.price_color')
if price_elem:
raw = price_elem.text.strip()
match = re.search(r'(\d+\.\d{2})', raw.replace(',', ''))
if match:
price = float(match.group(1))
return product_name, price
Step 6: Implement Price Drop Detection
Create tracker.py to orchestrate everything:
import time
from database import init_db, save_price, get_last_price
from scraper import get_product_info
# Define products to track: URL and target price
PRODUCTS = [
{
'url': 'http://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html',
'target_price': 45.00,
'name': 'A Light in the Attic' # optional fallback
},
# Add more products here
]
def check_product(product):
url = product['url']
target = product['target_price']
print(f"Checking {url}...")
name, current_price = get_product_info(url)
if current_price is None:
print(f" Failed to extract price for {url}")
return
print(f" {name} - Current price: {current_price}")
# Save to database
save_price(url, name, current_price)
# Check price drop compared to last recorded price
last_price = get_last_price(url)
if last_price and current_price < last_price:
drop_amount = last_price - current_price
print(f" PRICE DROP! Down by {drop_amount:.2f}")
# We'll send notification later
# Check if target reached
if current_price <= target:
print(f" TARGET REACHED! Price {current_price} <= {target}")
# Send alert
def run_tracker():
init_db()
for product in PRODUCTS:
check_product(product)
time.sleep(2) # Be polite: wait between requests
if __name__ == '__main__':
run_tracker()
Step 7: Add Email Notifications
We’ll send emails using Gmail’s SMTP.
For security, use an App Password (not your regular password).
Create notify.py:
import smtplib
from email.message import EmailMessage
import os
from dotenv import load_dotenv
load_dotenv() # Load EMAIL_ADDRESS and EMAIL_PASSWORD from .env
SMTP_SERVER = 'smtp.gmail.com'
SMTP_PORT = 587
def send_alert(product_url, product_name, current_price, target_price=None, drop_from=None):
"""Send an email notification about price change or target reached."""
sender = os.getenv('EMAIL_ADDRESS')
password = os.getenv('EMAIL_PASSWORD')
recipient = os.getenv('ALERT_RECIPIENT', sender) # default to same as sender
if not sender or not password:
print("Email credentials missing. Set EMAIL_ADDRESS and EMAIL_PASSWORD in .env")
return
subject = f"Price Alert: {product_name}"
if drop_from is not None:
body = f"Price dropped from {drop_from:.2f} to {current_price:.2f}. Check it out: {product_url}"
elif target_price is not None:
body = f"Target price reached! Current price {current_price:.2f} <= {target_price:.2f}. {product_url}"
else:
body = f"Price update: {product_name} is now {current_price:.2f}. {product_url}"
msg = EmailMessage()
msg.set_content(body)
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = recipient
try:
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.starttls()
server.login(sender, password)
server.send_message(msg)
print(f"Alert sent to {recipient}")
except Exception as e:
print(f"Failed to send email: {e}")
Now integrate into tracker.py:
from notify import send_alert
# Inside check_product, after detecting drop:
if last_price and current_price < last_price:
send_alert(url, name, current_price, drop_from=last_price)
if current_price <= target:
send_alert(url, name, current_price, target_price=target)
Step 8: Schedule the Tracker
For a production tracker, you’d use cron. But for simplicity, we’ll use the schedule library to run every hour.
Create scheduler.py:
import schedule
import time
from tracker import run_tracker
def job():
print("Running scheduled price check...")
run_tracker()
print("Done. Next run in 1 hour.")
# Schedule every hour at minute 0
schedule.every().hour.at(":00").do(job)
print("Price tracker scheduler started. Press Ctrl+C to stop.")
job() # run once immediately
while True:
schedule.run_pending()
time.sleep(60) # check every minute
Run with python scheduler.py. To run forever on a server, use systemd or a process manager like supervisor.
Step 9: Handle Multiple Products and Configuration
Move product list to a JSON config file config.json:
{
"products": [
{
"url": "http://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"target_price": 45.00
},
{
"url": "http://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
"target_price": 30.00
}
],
"alert_recipient": "your@email.com"
}
Then load it:
import json
with open('config.json') as f:
config = json.load(f)
PRODUCTS = config['products']
Conclusion
With under 200 lines of Python code, you have yourself a complete ecommerce price tracker.
It has the capacity to scrape product prices, detect drops and rises, store historical price data, and initiate email alerts.
This foundational development can e used to create any type of tracker – from stock price trackers to concert ticket availability trackers.
When developing a price tracker, ensure you structure your code for maintainability while adhering to the site’s terms and conditions.
Next steps to improve this price tracker:
Include a web dashboard using Flask or FastAPI to visualize price history charts.
Integrate with Selenium to handle JavaScript-heavy sites like Zillow or Nike.
Deploy to a VPS and run the scheduler 24/7.
Add additional options for notifications – Slack, Discord, or Telegram.
