Last active
August 29, 2015 13:56
-
-
Save jashsu/8954912 to your computer and use it in GitHub Desktop.
Spyglass is an email notification script for the Glass Shop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" Spyglass is an email notification script for the Glass Shop. | |
Setup: | |
------ | |
Install Python 2.7.x and these additional libraries: requests, lxml. | |
Enter your own smtp server, smtp login details and notification email | |
recipient into the relevant fields in Spyglass.__init__. In order for | |
Spyglass to fetch the page, you will also need to copy the cookie | |
strings from an authenticated browser session (get this by logging | |
into Google on your browser, visiting getglass, and then open the | |
debugger and copy the cookie data from the getglass HTTP request) | |
If you want to use gmail as your smtp server and you have two-factor | |
authentication enabled, generate an application-specific password here: | |
https://accounts.google.com/b/0/IssuedAuthSubTokens?hide_authsub=1 | |
Finally, uncomment the self.wishlist line(s) of the item(s) you want | |
to monitor. | |
btc: 1PEEenEG7ENJUx12wHjF8aTZBqjXmqTci7 | |
""" | |
import requests, re, json, time, smtplib, sys | |
from email.MIMEMultipart import MIMEMultipart | |
from email.MIMEText import MIMEText | |
from lxml import etree | |
from StringIO import StringIO | |
class ProgressBar(object): | |
def __init__(self): | |
self.counter = 0 | |
def increment(self, n=1): | |
self.counter += n | |
def draw(self, tick='.'): | |
draw_out = '' | |
if self.counter % 50 == 0: draw_out += '\n[{}] '.format(time.ctime()) | |
if self.counter % 10 == 0: draw_out += tick # For optional fancier gfx | |
else: draw_out += tick | |
sys.stdout.write(draw_out) | |
sys.stdout.flush() | |
def update(self, tick='.', n=1): | |
self.draw(tick=tick) | |
self.increment(n=n) | |
class Spyglass(object): | |
def __init__(self): | |
self.progbar = ProgressBar() | |
self.session = requests.Session() | |
self.smtp = smtplib.SMTP() | |
self.getglass_url = 'https://glass.google.com/getglass' | |
self.delay = 600 #check every 10 minutes | |
# vvv---FILL IN YOUR OWN DETAILS BELOW---vvv | |
self.smtp_server = ('smtp.gmail.com', 587) | |
self.email_user = '[email protected]' | |
self.email_pass = 'examplepassword' | |
self.email_recipient = '[email protected]' | |
self.cookies = { | |
'APISID': '', | |
'HSID': '', | |
'NID': '', | |
'PREF': '', | |
'SAPISID': '', | |
'SID': '', | |
'SSID': '', | |
'_ga': ''} | |
self.wishlist = { | |
# 6: u'Shale Glass', | |
# 7: u'Charcoal Glass', | |
# 8: u'Cotton Glass', | |
# 9: u'Tangerine Glass', | |
# 10: u'Sky Glass', | |
# 1001: u'Cable and Charger', | |
# 1002: u'Pouch', | |
# 2001: u'Mono Earbud', | |
# 2002: u'Stereo Earbuds', | |
# 3001: u'Active Shade', | |
# 3002: u'Classic Shade', | |
# 3003: u'Edge Shade', | |
# 3004: u'Clear Shield', | |
# 4001: u'Curve Shale Glass Frame', | |
# 4002: u'Curve Charcoal Glass Frame', | |
# 4003: u'Curve Cotton Glass Frame', | |
# 4004: u'Curve Tangerine Glass Frame', | |
# 4005: u'Curve Sky Glass Frame', | |
# 4011: u'Bold Shale Glass Frame', | |
4012: u'Bold Charcoal Glass Frame', | |
4013: u'Bold Cotton Glass Frame', | |
# 4014: u'Bold Tangerine Glass Frame', | |
# 4015: u'Bold Sky Glass Frame', | |
# 4021: u'Thin Shale Glass Frame', | |
# 4022: u'Thin Charcoal Glass Frame', | |
# 4023: u'Thin Cotton Glass Frame', | |
# 4024: u'Thin Tangerine Glass Frame', | |
# 4025: u'Thin Sky Glass Frame', | |
# 4031: u'Split Shale Glass Frame', | |
# 4032: u'Split Charcoal Glass Frame', | |
# 4033: u'Split Cotton Glass Frame', | |
# 4034: u'Split Tangerine Glass Frame', | |
# 4035: u'Split Sky Glass Frame', | |
} | |
# ^^^---FILL IN YOUR OWN DETAILS ABOVE---^^^ | |
def fetch_data(self): | |
response = self.session.get(self.getglass_url, cookies=self.cookies) | |
response_tree = etree.parse(StringIO(response.text), etree.HTMLParser(encoding = 'UTF-8')) | |
a = response_tree.xpath('//*[@id="contentPane"]/script[contains(., "AF_initDataCallback({key: \'ds:0")]') | |
b = re.findall(r'data:(.*?)}', a[0].text, re.DOTALL|re.MULTILINE) | |
assert(len(b) == 1) | |
c = re.sub(r'(,)\1+', r'\1', b[0]) | |
d = json.loads(c) | |
data = {i[0]: i[1:] for i in d[1]} | |
return data | |
def send_email(self, item_name, item_id): | |
self.smtp.connect(*self.smtp_server) | |
self.smtp.ehlo() | |
self.smtp.starttls() | |
self.smtp.login(self.email_user, self.email_pass) | |
message = MIMEMultipart() | |
message['From'] = 'noreply' | |
message['To'] = self.email_recipient | |
message['Subject'] = 'ALERT: {} is in stock'.format(item_name) | |
html = """\ | |
<html> | |
<head></head> | |
<body> | |
<p>{item_name} is in stock.<br><br> | |
Visit <a href="https://glass.google.com/getglass">https://glass.google.com/getglass</a> to place an order. | |
</p> | |
</body> | |
</html> | |
""".format(item_name=item_name) | |
message.attach(MIMEText(html, 'html')) | |
self.smtp.sendmail('noreply', self.email_recipient, message.as_string()) | |
self.smtp.close() | |
self.progbar.update(tick='x') | |
def monitor(self): | |
sys.stdout.write('[{}] Monitoring items {}...'.format(time.ctime(), str(self.wishlist.keys()))) | |
sys.stdout.flush() | |
done = False | |
while not done: | |
data = self.fetch_data() | |
for item_id in self.wishlist.keys(): | |
if data[item_id][4] == 1: | |
self.send_email(item_name=data[item_id][5][1], item_id=item_id) | |
del self.wishlist[item_id] | |
self.progbar.update() | |
if len(self.wishlist) == 0: | |
done = True | |
else: | |
time.sleep(self.delay) | |
def main(args): | |
myspyglass = Spyglass() | |
myspyglass.monitor() | |
sys.stdout.write('\n\n') | |
if __name__ == '__main__': | |
sys.exit(main(sys.argv)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment