There are plenty, I mean dozens if not hundreds of price tracking tools out there, the most famous probably being camelcamelcamel. This is a fun little project for people who want their own local solution for learning purposes whether you want to practice your Python or test out something new in Zabbix.

External Scripts with Python

If you aren’t interested in Python Scripting the source code for the script is available on my GitHub Repository. Along with templates for the hosts and templates themselves.

First if you don’t know what an External Script in Zabbix it is essentially any custom script used to produce an output that can be monitored, whether that is an integer, float or string.

I have recently found a fondness of magnetic knife blocks and I would like a nice one for my Chef’s Knives. I have a local Zwilling store to me but due to the current global pandemic that is Coronavirus it has closed.

The target knifeblock, fancy thick wood and far too expensive for me at full price

So as has become custom whenever I start a new project I will immediately check to see if there is a library. As Zwilling is not a tech company it is of no surprise they do not have an API available for easily following their prices.

So let’s start by throwing together a quick function that will extract the price off of the webpage. I’ve landed on using Beautiful Soup a great library for parsing HTML however it doesn’t exist within the standard library so in Ubuntu I installed this first.

pip3 install lxml bs4

Now pretty quickly I have thrown together a very brief script which returns to me the price of any item on Zwilling’s website given the item’s URL as an argument.

#!/usr/bin/env python3 ''' Script for extracting the price of item's on the Zwilling website ''' import requests from bs4 import BeautifulSoup import sys import json # 'https://uk.zwilling-shop.com/Kitchen-World/Kitchen-Knives/Knife-accessories/Knife-blocks-empty/Knife-block-bamboo-magnet-Zwilling-35046-110-0.html' def obtain_price(url): try: response = requests.get(url) except: exit('Failed to perform GET of URL: ' + url) soup = BeautifulSoup(response.text, 'lxml') price = soup.h1.find(attrs={'itemprop':'price'}).text.strip().lstrip().replace('£','') print(price) return def main(): URL = sys.argv[1] obtain_price(URL) return if __name__ == '__main__': main()

OK great so let’s take a look at the output, just a simple stripped down float.

Simple price extraction returning price as a float

Now astonishingly enough I checked the Sales page at Zwilling and the script worked to extract the price immediately, that’s a first I assure you.

This is a good start but let’s take it a step further, Zwilling are also prepared to let me know if the item goes out of stock. This seems like a pretty important considering I can’t purchase the knife block if it goes out of stock.

def obtain_availability(url): ''' Returns 1 if item is available or 0 if not ''' try: response = requests.get(url) except: exit('Failed to perform GET of URL: ' + url) soup = BeautifulSoup(response.text, 'lxml') results = soup.h1 content = results.find('meta', attrs={'itemprop':'availability'})['content'] if content == 'InStock': availability = 1 else: availability = 0 return print(availability) def main(): URL = sys.argv[1] if sys.argv[2] == 'price': obtain_price(URL) elif sys.argv[2] == 'availability': obtain_availability(URL) return

Adding this function and a small if allows me to decide whether I want to return availability or price through the second argument passed to the script, ‘price’ or ‘availability’ respectively.

Availability returns as 1 or 0 if the item is in or out of stock

Adding the Script to Zabbix

So if you aren’t familiar with using external scripts with Zabbix it’s a remarkably simple concept. First the script needs to be placed into the directory /usr/lib/zabbix/externalscripts by default, this can be changed in zabbix_server.conf by setting the parameter ExternalScripts.

Now just double check that you have executable permissions set by Zabbix and that the Zabbix user is set as the owner of the script.

Now we are finally ready to begin monitoring each of the items. I am going to separate each item into it’s own host in Zabbix, this will allow me to take advantage of some Macros and if I want in the future Host Screens.

Configuring the Zabbix Template

So first things first let’s create a template that we can apply to any host, or product in this case. The template for now will include items for both price and availability as well as a graph plotting both so that we have a single page we can check.

The template is available to download from GitHub so grab a copy and import it into Zabbix just navigate to Configuration -> Hosts on the navbar and the Import button will be top right.

As you can see from the template item we have been able to call the price_checker.py script as a key. After calling the script to pass in the arguments of URL and whether we are looking for price or availability we simply open square brackets.

Now to configure the Triggers. At the moment because this is a new alert I am just intrigued to know whenever a change occurs. Usually I’d be only alerting if the price decreased or the item has become available again but for now any change seems interesting enough.

As this is a simple trigger I am going to use the Add button on the Expression and because I am happy to hear about any changes I can use the abschange function and look for any non 0 results for both price and availability

Any price change

Any change in availability

Resulting two triggers

Now I could set higher priority alerts for if the price drops as that’s what I really care about but for now this will work.

Lastly just to show the simple graph that will allow us to see a history of availability against price.

Zabbix simple graph configuration, price against availability over time

That’s it for the template simply two items, two triggers and a graph will suffice for now.

Configuring the Zabbix Host

I have created a fairly simple host, the monitored address doesn’t matter in this case as we aren’t actually using it for anything so I have just left it pointing to localhost. I did create a new hostgroup called “Price Tracker” in case I fancy monitoring a few other things from the Zwilling website.

Next step, assign the template to the host.

As we need to call the Macro from an Item we cannot unfortunately use the inbuilt Inventory Items for URL.A/B/C so we need to create Host Macros. I have created {$URL} and set it equal to the URL of the item I want to monitor.

That’s it! Once the template is assigned to the host we are ready to start monitoring. As we are only checking the values once every 6 hours just to make certain the checks are working I use the “Check Now” function.

Graph configured in template plotting

If you would like to download the template, script and host so that you can upload the full solution straight into any Zabbix solution you are running please just head over to the GitHub repo and you can import zbx_export_hosts.xml.

If you have read this far please do drop a comment below and let me know if you’d like to see this project carried forwards and what further development would interest you.

01/05/2020 UPDATE: The first price drop of a whopping great 30% was alerted to me this morning. At least I knew before it sold out.