AmzTrack: Track Amazon Prices with Python

Shop Smarter, Sleep Better with Automated Amazon Price Tracking

ยท

11 min read

AmzTrack: Track Amazon Prices with Python

Hello there, fellow savvy shoppers and Pythonistas! If you've ever wanted to keep an eye on the price of a product on Amazon without manually refreshing the page every five minutes, this blog post is for you. Today, I'll share with you a simple Python script that I created, which will allow you to track Amazon prices right from your laptop or server, regardless of the operating system you use.

And the best part? It's free and easy to use.

So, let's get started!

Part 1: Meet your new friend, @BotFather

Before we dive into the code, you'll need a Telegram Bot token if you want to get constant price updates in Telegram. Don't worry; getting one is simple. Go to your Telegram app and search for a bot named @BotFather. It will generate a new bot and provide you with a token. Keep this token safe; you will need it to interact with your bot. Replace <TELEGRAM BOT TOKEN> in the script with your token.

Part 2: The Price Tracking Alternatives

There are a few websites out there like pricehistoryapp.com and pricebefore.com that track prices. However, these services aren't always reliable. They might not update in real time, they may only work with certain products, or they could stop functioning if the website changes its layout.

Web scraping services like webscraping.ai can provide more precise and customizable results, but they also come with a cost. If all you need is a simple tracker, it might not be worth paying for these services.

Part 3: The Art of Web Scraping

Here's where things get interesting. To fetch the prices, our script uses a method called "web scraping", which is a way to extract data from websites. Amazon does not like this and uses techniques such as IP blocking and CAPTCHA challenges to prevent it. Using a residential IP address can help bypass some of these obstacles, but be aware that excessive or inappropriate scraping can still lead to your IP getting blocked.

So, remember, with great power comes great responsibility. Use your scraping powers wisely!

Part 4: See the Magic

  1. Install Python and the necessary libraries: First, you need to have Python installed on your computer. If you don't have it, download it from here. Once Python is installed, open your terminal or command prompt and type the following commands to install the necessary Python libraries: pip install requests beautifulsoup4 urllib3==2.0.4.

    You'd also want pip install fastapi uvicorn if you want to run it as a server.

  2. Get your Telegram Bot Token and Chat ID: Follow the steps described in the blog post. Once you have these, keep them handy as you will need to put them into your Python script.

  3. Get the Product URL: Go to the Amazon product page you want to track and copy its URL.

  4. Get Telegram chat_id and optionally Amazon browser cookies:

    For chat_id, start by sending your bot a message in Telegram. Then, run the provided script with your bot token. This will return your chat_id in the response.

     import requests
     TOKEN = <YOUR TELEGRAM TOKEN HERE>
     url = f"https://api.telegram.org/bot{TOKEN}/getUpdates"
     print(requests.get(url).json())
    

    For cookies, it's optional even if you're using the server implementation. You can obtain them by opening the product page in your local Chrome browser for example, copying the cookies, and formatting them into a Python dictionary. Replace the cookie dictionary in the script with your own.
    Tip: I selected all the cookies and asked GPT to format it into a Python dict. ๐Ÿ˜‰

  5. Edit the Python script: Now you need to replace some placeholders in the script with the values you just collected:

    • Replace <TELEGRAM BOT TOKEN> with your Telegram Bot Token.

    • Replace <CHAT_ID> with your chat_id.

    • Replace <Your Product URL> with the product URL.

    • Replace <Your Cookie> with the cookies dictionary you have collected (optional)

    • Set the TARGET variable to the price point at which you want to be alerted.

  6. Run the script: Save the script as a .py file (for example, base.py). Now, go to your terminal or command prompt, navigate to the directory where you saved the script and type: python base.py and hit Enter. The script should now run and send you updates on Telegram every 2 minutes!

Remember, this script will stop running if you close the terminal or shut down your computer. If you want the script to run continuously, you will have to set up your computer to prevent it from sleeping, or run the script on a server.

If you're on a Mac, use these commands to disable sleep mode and run the script as a continuous process:

sudo pmset -b sleep 0; sudo pmset -b disablesleep 1
nohup caffeinate python base.py &

When you're finished, re-enable sleep mode with:

sudo pmset -b sleep 5; sudo pmset -b disablesleep 0

You can do this similarly on Linux and disable sleep and network sleep from Power Management in Windows.

And there you have it! You're now set to never miss a price drop on your favorite Amazon product again. Happy shopping and happy coding!

Part 5: Complete Code with Brief Explanation

I've created two Python scripts for you. One is a base script that you can run from any device on your home network. The other is a FastAPI script if you want to run it as a server process. Here's what they do:

Base Script (You Probably only need this)

First, the script uses a requests.get call to fetch the HTML content of the Amazon product page. We send along headers that mimic a browser to prevent getting blocked by Amazon. It then uses BeautifulSoup to parse the HTML and extract the prices from specific tags.

The script checks two prices for verification. If the prices match, it sends a message to a specified Telegram chat with the current price. If the prices do not match, it sends an alert. If the price drops below a certain target, it sends a different alert.

## Base script

import requests
from bs4 import BeautifulSoup
from time import sleep

TOKEN = <TELEGRAM BOT TOKEN>
CHAT_ID = <YOUR CHAT ID>
TELEGRAM_API_URL = f"https://api.telegram.org/bot{TOKEN}/sendMessage"
PRODUCT_URL = "https://www.amazon.in/POCO-Pro-Yellow-128GB-Storage/dp/B0B6GDLMQK/ref=sr_1_1?crid=3EB9ZPVILWI2J&keywords=poco+x4+pro+5g&qid=1690330911&sprefix=poco+x4+pro%2Caps%2C243&sr=8-1"
TARGET = 17000  #INSERT YOUR TARGET PRICE HERE

def get_prices(url=PRODUCT_URL):
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0"}
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.content, "html.parser")

    input_tag = soup.find('input', {'id': 'attach-base-product-price'})
    price_primary = float(input_tag['value'])

    price_tag = soup.find('span', {'class': 'a-price-whole'})
    price_whole =float(price_tag.text.replace(',',''))
    return price_primary, price_whole

def send_telegram_message(message, chat_id = CHAT_ID):
    """Sends a message to a specified chat in Telegram."""
    data = {
        'chat_id': chat_id,
        'text': message
    }
    response = requests.post(TELEGRAM_API_URL, data=data)
    return response.json()

def main(args=None):
    """The main routine."""
    price_primary, price_whole = get_prices()
    if price_primary == price_whole:
        message = f'Price of product is {price_primary}'
        if price_primary <= TARGET:
            message = f'ALERT PRICE DROP Price of product is {price_primary}'
    else:
        message = f'Price mismatch for product between {price_primary} and {price_whole}'
        if price_primary <= TARGET or price_whole <= TARGET:
            message = f'ALERT PRICE DROP WITH MISMATCH Price of product is {min(price_primary,price_whole)}'
    send_telegram_message(message)

if __name__ == "__main__":
    while True:
        main()
        sleep(60*5)

Server Script

The server script does the same thing, but it's designed to run as a FastAPI process. This script uses cookies to maintain a session, which you will need to replace them with your own. The check will happen each time the check_price function runs which happens when the / route is hit.

from fastapi import FastAPI
import requests
from bs4 import BeautifulSoup

app = FastAPI()

TOKEN = <TELEGRAM BOT TOKEN>
CHAT_ID = <YOUR CHAT ID>
TELEGRAM_API_URL = f"https://api.telegram.org/bot{TOKEN}/sendMessage"
PRODUCT_URL = "https://www.amazon.in/POCO-Pro-Yellow-128GB-Storage/dp/B0B6GDLMQK/ref=sr_1_1?crid=3EB9ZPVILWI2J&keywords=poco+x4+pro+5g&qid=1690330911&sprefix=poco+x4+pro%2Caps%2C243&sr=8-1"
TARGET = 17000  #INSERT YOUR TARGET PRICE HERE

headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) \
        Gecko/20100101 Firefox/91.0"
    }

cookies = {
    "csm-hit": "tb:s-CXXNPATX9J2QGP81Q|1690349188202&t:169034999&adb:adblk_no",
    "session-token": "W842UvQcRIpJHNyfBrqtjds14fUwP7OoBTeIDrLCLpKks+uFGi6hZrn7H8DGUC8IJTdsfQsq6jgGzhGXho0oiA0TbhE9BHUAs8ZlJ2YsuUA4CMLLb6csSo/xAUwULgrLE6fVdZf/fwhHbBMt+XpuKnBoSSRHYe+VnWgrCxeN8cx7VXBD5gNf1+DbPnpcvF53DFaOBg+Zj0QN6KJsvZCsVdR/4pXJHllCvr0Y=",
    "ubid-acbin": "247-6048695-6105069",
    "i18n-prefs": "INR",
    "lc-acbin": "en_IN",
    "session-id-time": "2083786201l",
    "session-id": "253-7064393-874941",
}

def get_prices(url=PRODUCT_URL):

    sess = requests.Session()
    sess.headers.update(headers)
    sess.cookies.update(cookies)
    response = sess.get(url)
    soup = BeautifulSoup(response.content, "html.parser")

    input_tag = soup.find("input", {"id": "attach-base-product-price"})
    price_primary = float(input_tag["value"])

    price_tag = soup.find("span", {"class": "a-price-whole"})
    price_whole = float(price_tag.text.replace(",", ""))
    return price_primary, price_whole

def send_telegram_message(message, chat_id=CHAT_ID):
    """Sends a message to a specified chat in Telegram."""
    data = {"chat_id": chat_id, "text": message}
    response = requests.post(TELEGRAM_API_URL, data=data, timeout=20)
    return response.json()

@app.get("/")
def check_price():
    message = ''
    try:
        price_primary, price_whole = get_prices()
        if price_primary == price_whole:
            message = f"Price of product is {price_primary}"
            if price_primary <= TARGET:
                message = f"ALERT PRICE DROP Price of product is {price_primary}"
        else:
            message = (
                f"Price mismatch for product between {price_primary} and {price_whole}"
            )
            if price_primary <= TARGET or price_whole <= TARGET:
                message = f"ALERT PRICE DROP WITH MISMATCH Price of product is {min(price_primary,price_whole)}"
    except Exception as e:
        message = f"Error: {str(e)}"
    finally:
        send_telegram_message(message)
        return {"message": message}

Part 6: Detailed Code Walkthrough

Here we walk through the code line by line, feel free to skip this if you're not looking to add features to the tool. But if you're looking to customize this even further, the sky is the limit, let's delve into it.

import requests
from bs4 import BeautifulSoup
from time import sleep

Here, we're importing necessary Python libraries. requests allows us to send HTTP requests, BeautifulSoup is used for pulling data out of HTML and XML files, and sleep from time will help us to pause the execution of the script for a specified amount of time.

TOKEN = <TELEGRAM BOT TOKEN>
CHAT_ID = <YOUR CHAT ID>
TELEGRAM_API_URL = f"https://api.telegram.org/bot{TOKEN}/sendMessage"
PRODUCT_URL = "https://www.amazon.in/POCO-Pro-Yellow-128GB-Storage/dp/B0B6GDLMQK/ref=sr_1_1?crid=3EB9ZPVILWI2J&keywords=poco+x4+pro+5g&qid=1690330911&sprefix=poco+x4+pro%2Caps%2C243&sr=8-1"
TARGET = 17000  #INSERT YOUR TARGET PRICE HERE

In these lines, we're setting up our variables. TOKEN is your Telegram Bot Token, TELEGRAM_API_URL is the URL for the Telegram API for sending messages, PRODUCT_URL is the URL for the Amazon product you want to track, and TARGET is the price point at which you want to be alerted.

def get_prices(url=PRODUCT_URL):
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0"}
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.content, "html.parser")

This is the start of the get_prices function. We define a headers dictionary with a User-Agent to mimic a real browser. We then send a GET request to the product URL and parse the HTML content with BeautifulSoup.

input_tag = soup.find('input', {'id': 'attach-base-product-price'})
price_primary = float(input_tag['value'])

Here, we're looking for an HTML 'input' tag with the ID 'attach-base-product-price'. This is where Amazon stores the base product price. We retrieve it and convert it to a float.

price_tag = soup.find('span', {'class': 'a-price-whole'})
price_whole =float(price_tag.text.replace(',',''))
return price_primary, price_whole

Next, we're finding the span tag with the class 'a-price-whole' which contains the displayed price on the product page. We're extracting the text, removing any commas, converting it to a float and returning both prices.

def send_telegram_message(message, chat_id = CHAT_ID):
    """Sends a message to a specified chat in Telegram."""
    data = {
        'chat_id': chat_id,
        'text': message
    }
    response = requests.post(TELEGRAM_API_URL, data=data)
    return response.json()

This is the send_telegram_message function. It takes a message and a chat_id as inputs, creates a dictionary with these values, and sends a POST request to the Telegram API to send the message. We send the messages by calling send_telegram_message(message)

def main(args=None):
    """The main routine."""
    price_primary, price_whole = get_prices()
    if price_primary == price_whole:
        message = f'Price of product is {price_primary}'
        if price_primary <= TARGET:
            message = f'ALERT PRICE DROP Price of product is {price_primary}'
    else:
        message = f'Price mismatch for product between {price_primary} and {price_whole}'
        if price_primary <= TARGET or price_whole <= TARGET:
            message = f'ALERT PRICE DROP WITH MISMATCH Price of product is {min(price_primary,price_whole)}'

In the main function, we call the get_prices function to get the two price values.

We're checking if the base product price and displayed price are the same. If they are, we're creating a message with the price, and if it is less than or equal to the target, we're creating an alert message. If the prices are not the same, we're creating a message to notify about the mismatch and creating an alert message if either price is less than or equal to the target. You can customize the messages in the if-else block as you wish.

if __name__ == "__main__":
    while True:
        main()
        sleep(60*5)

Finally, if this script is being run directly (and not being imported as a module), we're calling the main function in an infinite loop, with a pause of 5 minutes (60*5) between each call. This will keep checking the prices and sending updates to Telegram. You can also remove the infinite loop and just call the main function, handling the scheduling in a Cron Job, if you'd prefer, that'd also save a bit of OS resources.

Conclusion

And voila! You've just created your very own Python-based Amazon price tracker. With the power of Python and a little bit of your time, you've built a tool that can save you both time and money. No longer do you need to manually keep track of fluctuating prices or pay for pricey tracking services. Now, you can have updates delivered right to you via Telegram.

Whether you're a bargain hunter or just love tinkering with Python, this script gives you a new tool in your arsenal. Plus, you've learned valuable skills in web scraping, working with APIs, and scripting with Python. The best part? You can customize this script to fit your specific needs, whether it's tracking prices on different websites or setting different price thresholds.

I was able to help my girlfriend buy a mobile with this. See how the price jumps up at the end, that happened right after we made the purchase. We had set an alert at 17k, and got a deal within 2 days of running AmzTrack.

Remember, this script is a starting point, and the sky is the limit when it comes to customizing it. Want to track multiple items at once or receive alerts via different messaging platforms or on-call? Go ahead and modify it to your heart's content. After all, that's the beauty of coding.

So, start saving money today with AmzTrack. It's a game-changer for online shopping. As always, happy coding and happy shopping!

Did you find this article valuable?

Support Aditya Jyoti Paul by becoming a sponsor. Any amount is appreciated!

ย