[O] Encapsulate telegram reporter

This commit is contained in:
Hykilpikonna
2022-03-03 00:18:24 -05:00
parent b4422848af
commit 4e93d80a68
3 changed files with 61 additions and 33 deletions
+7 -16
View File
@@ -1,12 +1,11 @@
import os import os
import time import time
import requests
from selenium.webdriver import Chrome from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from utils import parse_retry from utils import parse_retry, TelegramReporter, CSS
# Config # Config
# Telegram chat ID that receives update messages (could be a channel in @channel_id format) # Telegram chat ID that receives update messages (could be a channel in @channel_id format)
@@ -18,16 +17,8 @@ TG_TOKEN = os.environ['TG_TOKEN']
ALERT_RECEIVER = -1001655384423 ALERT_RECEIVER = -1001655384423
# Constants # Constants
CSS = By.CSS_SELECTOR
AVAIL_TABLE: dict[str, bool] = {} AVAIL_TABLE: dict[str, bool] = {}
TG = TelegramReporter(TG_TOKEN, TG_RECEIVER, ALERT_RECEIVER)
def send_message(msg: str):
r = requests.get(f'https://api.telegram.org/bot{TG_TOKEN}/sendMessage',
params={'chat_id': TG_RECEIVER, 'parse_mode': 'Markdown', 'text': msg})
if r.status_code != 200:
print('Request not OK:', r.status_code, r.text)
def parse_page(browser: Chrome): def parse_page(browser: Chrome):
@@ -41,7 +32,7 @@ def parse_page(browser: Chrome):
# Not available, check if it was previously available # Not available, check if it was previously available
if len(avail) == 0: if len(avail) == 0:
if title in AVAIL_TABLE: if title in AVAIL_TABLE:
send_message(f'Sold out: `{title}`') TG.send(f'Sold out: `{title}`')
del AVAIL_TABLE[title] del AVAIL_TABLE[title]
continue continue
@@ -58,11 +49,11 @@ def parse_page(browser: Chrome):
# Available and meets threshold criteria, notify user # Available and meets threshold criteria, notify user
AVAIL_TABLE[title] = True AVAIL_TABLE[title] = True
send_message(f'PS5 Became Available!\n' TG.send(f'PS5 Became Available!\n'
f'- [{title}]({link}) ${price:.2f}') f'- [{title}]({link}) ${price:.2f}')
# Check alert # Check alert
TG.alert()
if __name__ == '__main__': if __name__ == '__main__':
@@ -72,7 +63,7 @@ if __name__ == '__main__':
browser = Chrome(options=web_options) browser = Chrome(options=web_options)
browser.get('https://www.bestbuy.ca/en-ca/category/ps5-consoles/17583383') browser.get('https://www.bestbuy.ca/en-ca/category/ps5-consoles/17583383')
send_message('Bot started') TG.send('Bot restarted')
# parse_page(browser) # parse_page(browser)
# browser.close() # browser.close()
+11 -15
View File
@@ -7,7 +7,7 @@ from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from utils import parse_retry from utils import parse_retry, TelegramReporter, CSS
# Config # Config
# Price increase ratio threshold (ignore everything higher than this ratio) # Price increase ratio threshold (ignore everything higher than this ratio)
@@ -17,9 +17,10 @@ INCR_MAX = 0.2
TG_RECEIVER = '@toronto_bestbuy_gpu' TG_RECEIVER = '@toronto_bestbuy_gpu'
# Telegram bot token # Telegram bot token
TG_TOKEN = os.environ['TG_TOKEN'] TG_TOKEN = os.environ['TG_TOKEN']
# Alert receiver telegram chat ID
ALERT_RECEIVER = -1001655384423
# Constants # Constants
CSS = By.CSS_SELECTOR
MODELS = [ MODELS = [
['3060 ti', 400, 132], ['3060 ti', 400, 132],
['3070 ti', 600, 167], ['3070 ti', 600, 167],
@@ -34,6 +35,7 @@ USD_TO_CAD = 1.27
AVAIL_TABLE: dict[str, bool] = {} AVAIL_TABLE: dict[str, bool] = {}
IGNORED = [] IGNORED = []
TITLE_SHORTEN = re.compile('(rtx|nvidia|geforce|edition|gddr[56]x*|video|card)', flags=re.IGNORECASE) TITLE_SHORTEN = re.compile('(rtx|nvidia|geforce|edition|gddr[56]x*|video|card)', flags=re.IGNORECASE)
TG = TelegramReporter(TG_TOKEN, TG_RECEIVER, ALERT_RECEIVER)
def shorten_title(title: str): def shorten_title(title: str):
@@ -43,14 +45,6 @@ def shorten_title(title: str):
return short_title.strip() return short_title.strip()
def send_message(msg: str):
r = requests.get(f'https://api.telegram.org/bot{TG_TOKEN}/sendMessage',
params={'chat_id': TG_RECEIVER, 'parse_mode': 'Markdown', 'text': msg})
if r.status_code != 200:
print('Request not OK:', r.status_code, r.text)
def parse_page(browser: Chrome): def parse_page(browser: Chrome):
# Parse page # Parse page
for item in browser.find_elements(By.CLASS_NAME, 'x-productListItem'): for item in browser.find_elements(By.CLASS_NAME, 'x-productListItem'):
@@ -67,7 +61,7 @@ def parse_page(browser: Chrome):
# Not available, check if it was previously available # Not available, check if it was previously available
if len(avail) == 0: if len(avail) == 0:
if title in AVAIL_TABLE: if title in AVAIL_TABLE:
send_message(f'Sold out: `{title}`') TG.send(f'Sold out: `{title}`')
del AVAIL_TABLE[title] del AVAIL_TABLE[title]
continue continue
@@ -103,10 +97,10 @@ def parse_page(browser: Chrome):
# Available and meets threshold criteria, notify user # Available and meets threshold criteria, notify user
AVAIL_TABLE[title] = True AVAIL_TABLE[title] = True
send_message(f'{model[0].upper()} Became Available!\n' TG.send(f'{model[0].upper()} Became Available!\n'
f'\n' f'\n'
f'${price:.0f} | {price_incr * 100:.0f}% Incr | Value: {value:.0f}\n' f'${price:.0f} | {price_incr * 100:.0f}% Incr | Value: {value:.0f}\n'
f'- [{title}]({link})') f'- [{title}]({link})')
if __name__ == '__main__': if __name__ == '__main__':
@@ -120,6 +114,8 @@ if __name__ == '__main__':
# parse_page(browser) # parse_page(browser)
# browser.close() # browser.close()
TG.send('Bot restarted')
# Refresh indefinitely # Refresh indefinitely
while True: while True:
time.sleep(5) time.sleep(5)
+43 -2
View File
@@ -1,8 +1,15 @@
import traceback from __future__ import annotations
from typing import Callable
import traceback
from typing import Callable, Optional
import requests
from selenium.common.exceptions import StaleElementReferenceException from selenium.common.exceptions import StaleElementReferenceException
from selenium.webdriver.chrome.webdriver import WebDriver from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.common.by import By
CSS = By.CSS_SELECTOR
def parse_retry(parser: Callable, browser: WebDriver, tries: int = 0): def parse_retry(parser: Callable, browser: WebDriver, tries: int = 0):
@@ -13,3 +20,37 @@ def parse_retry(parser: Callable, browser: WebDriver, tries: int = 0):
parse_retry(parser, browser, tries + 1) parse_retry(parser, browser, tries + 1)
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
class TelegramReporter:
token: str
receiver: str | int
alert_receiver: Optional[str | int]
def __init__(self, token: str, receiver: str, alert_receiver: Optional[str | int]):
self.token = token
self.receiver = receiver
self.alert_receiver = alert_receiver
def send(self, msg: str, rec: Optional[str | int] = None) -> bool:
"""
Send a message
:param msg: Message string
:param rec: Receiver
:return: Success or not
"""
if rec is None:
rec = self.receiver
r = requests.get(f'https://api.telegram.org/bot{self.token}/sendMessage',
params={'chat_id': rec, 'parse_mode': 'Markdown', 'text': msg})
if r.status_code != 200:
print('Request not OK:', r.status_code, r.text)
return r.status_code == 200
def alert(self) -> bool:
if self.alert_receiver:
return self.send('/alert', self.alert_receiver)