├── Procfile ├── .gitignore ├── requirements.txt ├── amazon.sh ├── README.md ├── keyring.py └── amazon.py /Procfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | BeautifulSoup==3.2.1 2 | mechanize==0.2.5 3 | -------------------------------------------------------------------------------- /amazon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | function gnome-keyring-control() { 3 | local -a vars=( \ 4 | DBUS_SESSION_BUS_ADDRESS \ 5 | GNOME_KEYRING_CONTROL \ 6 | GNOME_KEYRING_PID \ 7 | XDG_SESSION_COOKIE \ 8 | ) 9 | local pid=$(ps -C gnome-session -o pid --no-heading) 10 | eval "unset ${vars[@]}; $(printf "export %s;" $(sed 's/\x00/\n/g' /proc/${pid//[^0-9]/}/environ | grep $(printf -- "-e ^%s= " "${vars[@]}")) )" 11 | } 12 | 13 | gnome-keyring-control 14 | python `dirname $0`/amazon.py 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | amazondailyapp 2 | ============== 3 | 4 | Some code I put together to purchase the Free Amazon App of the day. 5 | 6 | How to use 7 | ========== 8 | 9 | Invoke it with the correct command line options: 10 |
python amazon.py --username=username --password=password11 | 12 | Use the keyring.py to setup your gnome keyring with your amazon credentials. Then use amazon.sh daily in your cronjobs with the correct path to amazon.py. This script makes sure that the gnome keyring is initialized before running amazon.py. 13 | 14 | If you don't want to use gnome's keyring simply edit amazon.py and put your credentials there or use the command line options. 15 | 16 | Dependencies 17 | ============ 18 | 19 | You need to have mechanize, BeautifulSoup and gnomekeyring for python installed 20 | 21 | On Ubuntu Linux this should be enough: 22 |
pip install mechanize beautifulsoup23 | 24 | Heroku Modded 25 | ============= 26 | 27 | This script has been modified to be rid of any dependencies on GNOME. Create a new Heroku app. `heroku addons:add scheduler`. Set [scheduler](https://heroku-scheduler.herokuapp.com/dashboard) to run script with credentials in arguments daily. -------------------------------------------------------------------------------- /keyring.py: -------------------------------------------------------------------------------- 1 | import gnomekeyring 2 | import glib 3 | glib.set_application_name('Amazon daily app downloader') 4 | 5 | 6 | class Keyring(): 7 | """ Easy interface for Gnome-keyring.""" 8 | 9 | def __init__(self): 10 | if not gnomekeyring.is_available(): 11 | raise Exception("Gnome keyring not available!") 12 | self.keyring_name = gnomekeyring.get_default_keyring_sync() 13 | 14 | def set_password(self, key_name, user, password): 15 | return gnomekeyring.item_create_sync( 16 | self.keyring_name, 17 | gnomekeyring.ITEM_GENERIC_SECRET, 18 | key_name, 19 | {"user": user, 20 | "key_name": key_name}, 21 | password, 22 | True) 23 | 24 | def __get_credentials(self, key_name): 25 | try: 26 | items = gnomekeyring.find_items_sync( 27 | gnomekeyring.ITEM_GENERIC_SECRET, 28 | {"key_name": key_name}) 29 | return items[0].attributes["user"], items[0].secret 30 | except (gnomekeyring.DeniedError, gnomekeyring.NoMatchError): 31 | return None, None 32 | 33 | def get_user(self, key_name): 34 | return self.__get_credentials(key_name)[0] 35 | 36 | def get_password(self, key_name): 37 | return self.__get_credentials(key_name)[1] 38 | 39 | 40 | if __name__ == '__main__': 41 | kr = Keyring() 42 | kr.set_password('test_amazon', 'test_user', 'test_password') 43 | assert 'test_user' == kr.get_user('test_amazon') 44 | assert 'test_password' == kr.get_password('test_amazon') 45 | print "All tests OK." 46 | -------------------------------------------------------------------------------- /amazon.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | from optparse import OptionParser 5 | import mechanize 6 | from BeautifulSoup import BeautifulSoup 7 | import time,random 8 | # from keyring import Keyring 9 | import os 10 | 11 | didIbuy = False 12 | 13 | def getOptions(): 14 | arguments = OptionParser() 15 | arguments.add_options(["--username", "--password", "--firstyear"]) 16 | return arguments.parse_args()[0] 17 | 18 | def find_appstore(html): 19 | soup = BeautifulSoup(html) 20 | for link in soup.findAll("a", {"class":"nav_a nav_item"}): 21 | if link.find(text="Apps"): 22 | return link["href"] 23 | return None 24 | 25 | def isappfree(soup): 26 | if soup.find("span", {"class":"new-price"}, text="Free") == "Free": 27 | return True 28 | return False 29 | 30 | def getfreeapp(html, br): 31 | global didIbuy 32 | soup = BeautifulSoup(html) 33 | for widget in soup.findAll("div", {"class":"fad-widget-large"}): 34 | if isappfree(widget): 35 | br.select_form(name="handleBuy") 36 | appurchached = br.submit().read() 37 | #print appurchached 38 | didIbuy = True 39 | else: 40 | print "Free app not free!" 41 | 42 | if __name__ == '__main__': 43 | 44 | # kr = Keyring() 45 | #time.sleep(random.randint(1,120)) 46 | options = getOptions() 47 | 48 | br = mechanize.Browser() 49 | # br.set_proxies({"http":"localhost:8080"}) 50 | br.set_handle_robots(False) 51 | br.addheaders = [("User-agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.10 (maverick) Firefox/3.6.13")] 52 | 53 | sign_in = br.open("http://www.amazon.com/gp/flex/sign-out.html") 54 | 55 | br.select_form(name="sign-in") 56 | if options.username != None: 57 | br["email"] = options.username 58 | br["password"] = options.password 59 | # else: 60 | # while kr.get_user("Amazon") is None: 61 | # user = raw_input('Amazon user name:') 62 | # password = raw_input('Amazon password:') 63 | # ok = raw_input('Save (y/N)?').lower().startswith('y') 64 | # if ok: 65 | # kr.set_password("Amazon", user, password) 66 | # set your static credentials here if you want 67 | # br["email"] = kr.get_user("Amazon") 68 | # br["password"] = kr.get_password("Amazon") 69 | logged_in = br.submit().read() 70 | 71 | error_str = "The e-mail address and password you entered do not match any accounts on record." 72 | if error_str in logged_in: 73 | print error_str 74 | sys.exit(1) 75 | #print "Successfully logged in!" 76 | appstore_url = find_appstore(logged_in) 77 | if appstore_url == None: 78 | print "Appstore not found. Amazon site has changed!" 79 | sys.exit(0) 80 | for i in range(0,5): 81 | if appstore_url: 82 | appstore_html = br.open(appstore_url).read() 83 | getfreeapp(appstore_html,br) 84 | if didIbuy: 85 | sys.exit(0) 86 | print "I didn't buy the free app today! What's wrong with me? :(" 87 | --------------------------------------------------------------------------------