#!/usr/bin/python # -*- coding: utf-8 -*- import os import re import json import time import requests import smtplib import argparse import urlparse import datetime,random import UserAgent import telegram from copy import copy from lxml import html from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from datetime import date, datetime, timedelta ua = UserAgent.UserAgent() intervalTimeBetweenCheck = 0 dateIndex = datetime.now() emailinfo = {} IFTTT_Key = "" IFTTT_EventName = "" # msg_content format # msg_content['Subject'] = 'Subject' # msg_content['Content'] = 'This is a content' def send_Notification(msg_content): global send_Mode if send_Mode == 1: send_email(msg_content) elif send_Mode == 2: IFTTT_alert(msg_content) elif send_Mode == 3: telegram_alert(msg_content) def telegram_alert(msg_content): global botToken global chatId # 1 is success # 2 is server working msg # 3 is server shutdown if msg_content['code'] == 1: message = "Congratulations! " + str(msg_content['Price']) +" "+ msg_content['Product'] + " " + " " + msg_content['URL'] elif msg_content['code'] == 2: message = '🔴' + msg_content['Content'] elif msg_content['code'] == 3: message = msg_content['Content'] bot.send_message(chat_id=chatId, text=message) print "Mesage posted to telegram:",chatId def IFTTT_alert(msg_content): global IFTTT_EventName global IFTTT_Key requestBody = {} # 1 is success # 2 is server working msg # 3 is server shutdown if msg_content['code'] == 1: requestBody["value1"] = msg_content['Product'] requestBody["value2"] = msg_content['Price'] requestBody["value3"] = msg_content['URL'] elif msg_content['code'] == 2: requestBody["value1"] = msg_content['Content'] elif msg_content['code'] == 3: requestBody["value1"] = msg_content['Content'] url = "https://maker.ifttt.com/trigger/%s/with/key/%s" % (IFTTT_EventName,IFTTT_Key) requests.post(url, data=requestBody) print "IFTTT post success ",url def send_email(msg_content): global emailinfo try: # Try to login smtp server s = smtplib.SMTP("smtp.gmail.com:587") s.ehlo() s.starttls() s.login(emailinfo['sender'], emailinfo['sender-password']) except smtplib.SMTPAuthenticationError: # Log in failed print smtplib.SMTPAuthenticationError print('[Mail]\tFailed to login') else: # Log in successfully print('[Mail]\tLogged in! Composing message..') for receiver in emailinfo['receivers']: msg = MIMEMultipart('alternative') msg['Subject'] = msg_content['Subject'] msg['From'] = emailinfo['sender'] msg['To'] = receiver text = msg_content['Content'] part = MIMEText(text, 'plain') msg.attach(part) s.sendmail(emailinfo['sender'], receiver, msg.as_string()) print('[Mail]\tMessage has been sent to %s.' % (receiver)) # send notified mail once a day. def checkDayAndSendMail(): todayDate = datetime.now() start = datetime(todayDate.year, todayDate.month, todayDate.day) end = start + timedelta(days=1) global dateIndex # if change date if dateIndex < end : dateIndex = end # send mail notifying server still working msg_content = {} msg_content['Subject'] = '[Amazon Price Alert] Server working !' msg_content['Content'] = 'Amazon Price Alert still working until %s !' % (todayDate.strftime('%Y-%m-%d %H:%M:%S')) msg_content['Price'] = "" msg_content['Time'] = todayDate.strftime('%Y-%m-%d %H:%M:%S') msg_content['ServerState'] = "Working" msg_content['code'] = 2 # 2 is server state send_Notification(msg_content) def get_price(url, selector): # set random user agent prevent banning r = requests.get(url, headers={ 'User-Agent': ua.random(), 'Accept-Language': 'zh-tw', 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Connection':'keep-alive', 'Accept-Encoding':'gzip, deflate' }) r.raise_for_status() tree = html.fromstring(r.text) # find product name productName = "" productName_results = tree.xpath(selector['productname']) if not productName_results: # raise Exception("Product Name does not exist") print('Didn\'t find the \'product-name\' element, trying again later...') else : productName = productName_results[0].text productName = productName.strip() # find Price try: # extract the price from the string price_string = re.findall('\d+.\d+', tree.xpath(selector['price'])[0].text)[0] return float(price_string.replace(',', '')),productName except IndexError, TypeError: print('Didn\'t find the \'price\' element, trying again later...') # be banned, send mail then shut down # send mail notifying server shutdown msg_content = {} msg_content['Subject'] = '[Amazon Price Alert] Server be banned !' msg_content['Content'] = 'Amazon Price Alert be banned at %s !' % (datetime.now().strftime('%Y-%m-%d %H:%M:%S')) msg_content['Price'] = "" msg_content['Time'] = "" msg_content['ServerState'] = "Banned" msg_content['code'] = 3 # 3 is server shutdown send_Notification(msg_content) return 0,productName # read config json from path def get_config(config): with open(config, 'r') as f: # handle '// ' to json string input_str = re.sub(r'// .*\n', '\n', f.read()) return json.loads(input_str) # add some arguments def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('-c', '--config', default='%s/config.json' % os.path.dirname(os.path.realpath(__file__)), help='Add your config.json path') parser.add_argument('-t', '--poll-interval', type=int, default=780, help='Time(second) between checking, default is 780 s.') return parser.parse_args() def main(): #set up arguments args = parse_args() intervalTimeBetweenCheck = args.poll_interval global dateIndex global emailinfo global IFTTT_Key,IFTTT_EventName,send_Mode global botToken, chatId global bot dateIndex = datetime.now() # get config from path config = get_config(args.config) emailinfo = config['email'] intervalTimeBetweenCheck = config['default-internal-time'] send_Mode = config['send_Mode'] IFTTT_Key = config['IFTTT']['key'] IFTTT_EventName = config['IFTTT']['eventName'] botToken = config['Telegram']['botToken'] chatId = config['Telegram']['chatId'] #initialize telegram bot if send_Mode == 3: bot = telegram.Bot(botToken) #get all items to parse items = config['item-to-parse'] while True and len(items): nowtime = datetime.now() nowtime_Str = nowtime.strftime('%Y-%m-%d %H:%M:%S') print ('[%s] Start Checking' % (nowtime_Str)) # send mail notify system working everyday checkDayAndSendMail() itemIndex = 1 for item in copy(items): # url to parse item_page_url = urlparse.urljoin(config['amazon-base_url'], item[0]) print('[#%02d] Checking price for %s (target price: %s)' % ( itemIndex, item[0], item[1])) # get price and product name productName = item[2] price,productName = get_price(item_page_url, config['xpath_selector']) # Check price lower then you expected if not price: continue elif price <= item[1]: print('[#%02d] %s\'s price is %s!! Trying to send email.' % (itemIndex,productName,price)) msg_content = {} msg_content['Subject'] = '[Amazon] %s Price Alert - %s' % (productName,price) msg_content['Content'] = '[%s]\nThe price is currently %s !!\nURL to salepage: %s' % (nowtime_Str, price, item_page_url) msg_content['Price'] = price msg_content['URL'] = item_page_url msg_content['Product'] = productName msg_content['ServerState'] = "" msg_content['code'] = 1 # 2 is server state send_Notification(msg_content) items.remove(item) else: print('[#%02d] %s\'s price is %s. Ignoring...' % (itemIndex,productName,price)) itemIndex += 1 if len(items): # time interval add some random number for preventing banning nowtime = datetime.now() thisIntervalTime = intervalTimeBetweenCheck + random.randint(0,150) #calculate next triggered time dt = datetime.now() + timedelta(seconds=thisIntervalTime) print('Sleeping for %d seconds, next time start at %s\n' % (thisIntervalTime, dt.strftime('%Y-%m-%d %H:%M:%S'))) time.sleep(thisIntervalTime) else: break if __name__ == '__main__': main()