Woot Alerts with Python

## Why Yet Another Woot Alert System?

There are several Woot alert services out there. However, most of them require you to have a web browser window open, or would alert you via SMS and/or email upon every single item being offered by Woot, even during Woot-Offs. Some others just don’t work as advertised.

I found disadvantages associated to pretty much all the services I tried. Perhaps my needs are just too specific, so I decided to put together a customized alert system myself. These were my requirements:

  • Alerts should be sent to my cell phone through pushover.
  • Alerts should be sent only for products I’m interested in.
  • The system should keep a log of all the products posted (just for future reference).
  • The system should work with Woot-Offs.
  • All Woot websites (i.e. Wine, Shirt, Home, etc.) should be parsed.

What You Need

The backbone of this system is a Python script running in a Linux server/computer. You will need the following:

  • Python installed in your Mac, Linux box or windows PC.
  • The Python feedparser module. You can get it here.
  • Pushover account and app installed in your mobile device. You will also need the token and user strings from Pushover to be used in the script below (more info here).
  • Woot alert python script (see below).

The Code

Obligatory disclaimer: Although I worked with several programming languages in my college days, I don’t consider myself a programmer. I write scripts out of the enjoyment of creating things. Although all the scripts in this site work and do what they are supposed to do, they may not be written in the most elegant way. If you think you can improve them, feel free to so do, I’ve placed them in GitHub. You can also use part of this code as long as you link back to this site.

Here is the code for the script. I’ll go through the main sections below, but feel free to write a comment at the end of the post if you have questions.

In a nutshell, the script reads a text file with the list of words that will be searched for in each Woot item’s title. Depending on how you set it up, It’ll go through all Woot RSS feeds, read item by item and add them to text files (one per category). If the script finds any of the words it is looking for, it sends out a Pushover notification with some additional info related to that item.

:::python
import feedparser #need manual installation. Doesn't come with Python.
import os
import httplib #used by pushover
import urllib #used by pushover


# Linux:
folderPath = '/home/YOUR_USERNAME/Scripts/Support_Files/Woot/'

# Just woot.com items:
#url = "https://api.woot.com/1/sales/current.rss/www.woot.com"

# All woot feeds:
url = "http://api.woot.com/1/sales/current.rss"
alertsFile = folderPath+'alert_list.txt'
dealsFile = folderPath+'dealsgroup' #omit extension as it will be provided by the script.


def pushover(msg):

    conn = httplib.HTTPSConnection("api.pushover.net:443")
    conn.request("POST", "/1/messages.json",
        urllib.urlencode({
            "token": "YOUR-PUSHOVER-API-TOKEN",
            "user": "YOUR-PUSHOVER-API-USER",
            "message": msg,
    }), { "Content-type": "application/x-www-form-urlencoded" })
    conn.getresponse()



def inItemsList(wootTitle, fileIndex):
    ''' Checks if the item currently in woot.com was previously entered in the item_list.txt file. 
    If it was not, it enters it and returns the inList flag as False (i.e. it wasn't previously in the 
    list of items). Otherwise, it returns the flag as True (i.e. it is already in the list)'''

    inList=True
    fileStr = str(fileIndex)

    with open(dealsFile+'-'+fileStr+'.txt', 'a+') as itemList: #it opens or creates a file in the form of dealsgroup-1.txt

        try:
            lastLine = itemList.readlines()[-1].strip('\n')
        except IndexError:
            lastLine = ''
            ''' If the file is empty or does not exist, there will be an IndexError.
            Then, an arbitraty value is assigned to lastLine so that the script continues
            and the file is created'''

        if wootTitle==lastLine:
            inList=True
        else:
            itemList.write(wootTitle+'\n')
            inList=False

    return inList       


# Main Script

def main():

    parsedFeed = feedparser.parse(url)
    entryIndex = 0

    for entry in parsedFeed['entries']:

        entryIndex += 1

        try:
            # The feed only has one entry. Therefore, the data from index [4] is assigned.
            title = entry['title']
            soPercentage = entry['woot_soldoutpercentage']
            price = entry['woot_price']
            wootoff = entry['woot_wootoff']

        except IOError:
            print ('Variables could not be assigned based on parsed data')


        if not inItemsList(title, entryIndex):

            with open(alertsFile, 'r') as alertList:

                for alertName in alertList:

                    alertName = alertName.strip('\n').strip('\r')
                    # '\r' should be used to remove carriage return on *nix systems.
                    print alertName
                    print title

                    if  alertName in title:

                        print ('Item found in Alert List')
                        soPerInt = int(soPercentage)*100     
                        body = "Title: %s \nPrice: %s \nSold Out Percentage: %s%% \nWoot Off? %s\n" % (title, price, str(soPerInt), wootoff)
                        print ('Sending message to pushover')
                        pushover(body)

                    else:
                        print ('Item not found in Alert List')

        else:

            print ('Item already in Item List')


if __name__ == '__main__':
    main()

First, the python modules to be used are imported. Then, the folderPath variable is defined, which contains the path of the folder where the text files are located, you can edit this path to fit your needs. The url variable is defined depending on what feeds you want to parse (see script comments for more information). In the next lines, you will define the name of the file where the search words are (alertsFile variable) and the first part of name of the text files where the Woot items will be added (dealsFile variable).

Next, the function for sending messages to Pushover is defined. Remember to replace the token and user variables with your own Pushover credentials. Then, another function is created for checking if the currently posted item in Woot is in the the text file corresponding to that category (see the actual code for further details and comments on how this function works).

We then get to the main function, which is the glue between the functions above. The very first line is key, as it uses the feedparser module to parse the Woot feeds and store the result in the parsedFeed variable. In the following lines, the script iterates over parsedFeed, checks if the currently posted products are already in the text files defined above (through the inItemsList function). If they are, it doesn’t do anything and finishes the script (meaning the script already ran at least once and appended the currently posted Woot items to the text files). If, on the other hand, the posted Woot items are not in the text files, it appends them and checks if any of the item titles contain the words in the alertsFile variable. If that is the case, it sends a message through Pushover (by calling the pushover function).

Testing it Out

Ideally, you should set up some sort of recurrent task to run this script at regular intervals. I used to have an always-on Linux machine that would run this script every 2 minutes through Cron (more info on how to setup Cron here), but you can implement an equivalent setup on a Mac or a PC.

In order to test the script, you just need to include some words to search for in different lines within the alert_list.txt file (if you didn’t change the file name within the code above, that is). Then, run the script by typing python woot_alert.py, and assuming everything is set up the right way in your computer and phone, you should receive the following message:

Woot Alert

Tools Used in this Post

Python Script