Skip to content
This repository was archived by the owner on Feb 26, 2026. It is now read-only.

Commit 70b93c5

Browse files
authored
Merge branch 'tmxkn1:master' into feature_telegram
2 parents bd811a6 + 3162e63 commit 70b93c5

File tree

14 files changed

+135
-290
lines changed

14 files changed

+135
-290
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
**2021-08-01**
2+
3+
V2.0.3
4+
5+
- Added '--exit-on-finish' command line option.
6+
- Fixed a bug in getting quiz links.
7+
18
**2021-08-01**
29

310
V2.0.2

helper/browser.py

Lines changed: 64 additions & 214 deletions
Large diffs are not rendered by default.

msreward/account/login.py

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,8 @@ def log_in(self):
3838
time.sleep(1)
3939
self._click_i_look_good()
4040

41-
if self._browser.find_by_xpath(LOGIN_SIGN_IN_BUTTON_XPATH):
42-
self._browser.click_by_xpath(LOGIN_SIGN_IN_BUTTON_XPATH)
43-
self._browser.wait_until_visible(
44-
By.XPATH, '//*[@id="uhfLogo" or @id="microsoft"]', 10)
41+
self._browser.click_element(By.XPATH, LOGIN_SIGN_IN_BUTTON_XPATH, ignore_no_ele_exc=True)
42+
self._browser.wait_until_visible(By.XPATH, '//*[@id="uhfLogo" or @id="microsoft"]', 10)
4543

4644
self._log_into_bing_mobile() if self._browser.mobile_mode else self._log_into_bing_pc()
4745
time.sleep(1)
@@ -61,21 +59,21 @@ def _enter_password(self):
6159

6260
def _enter_otc(self):
6361
logging.debug(msg='OTC information is provided.')
64-
if not self._browser.find_elements_by_name(LOGIN_OTC_INPUT_NAME):
62+
if not self._browser.find_elements(By.NAME, LOGIN_OTC_INPUT_NAME):
6563
self._switch_to_otc_method()
6664
totp = pyotp.TOTP(self.otp_secret)
6765
otc = totp.now()
6866
self._enter_login_screen_value(LOGIN_OTC_INPUT_NAME, otc, 'Sent OTC')
6967

7068
def _switch_to_otc_method(self):
7169
logging.debug(msg='Switching to OTC verification method.')
72-
sign_in_another_way = self._browser.find_by_id('signInAnotherWay')
70+
sign_in_another_way = self._browser.find_elements(By.ID, 'signInAnotherWay')
7371
if not sign_in_another_way:
7472
raise FailToSignInException('Sign in is failed. Unable to switch to OTC verification method. Did not find the "sign in another way" link.')
7573

7674
sign_in_another_way[0].click()
7775
time.sleep(1)
78-
verificaiton_methods = self._browser.find_by_xpath('//div[@data-bind="text: display"]')
76+
verificaiton_methods = self._browser.find_elements(By.XPATH, '//div[@data-bind="text: display"]')
7977
for vm in verificaiton_methods:
8078
if 'mobile app' in vm.text:
8179
vm.click()
@@ -84,60 +82,43 @@ def _switch_to_otc_method(self):
8482
raise FailToSignInException(f'Sign in is failed. Unable to switch to OTC verification method. No such option. All options are:\n{[x.text for x in verificaiton_methods]}')
8583

8684
def _enter_login_screen_value(self, ele_name, value, msg):
87-
self._browser.wait_until_clickable(By.NAME, ele_name, 10)
88-
self._browser.send_key_by_name(ele_name, value)
85+
self._browser.wait_until_visible(By.NAME, ele_name, 10)
86+
self._browser.send_key(By.NAME, ele_name, value)
8987
logging.debug(msg=msg)
9088
time.sleep(0.5)
91-
self._browser.send_key_by_name(ele_name, Keys.RETURN)
89+
self._browser.send_key(By.NAME, ele_name, Keys.RETURN)
9290
time.sleep(0.5)
9391

9492
def sign_in_prompt(self):
9593
time.sleep(3)
96-
sign_in_prompt_msg = self._browser.find_by_class('simpleSignIn')
94+
sign_in_prompt_msg = self._browser.find_elements(By.CLASS_NAME, 'simpleSignIn')
9795
if sign_in_prompt_msg:
9896
logging.debug(msg='Detected sign-in prompt')
99-
self._browser.wait_until_clickable(By.LINK_TEXT, 'Sign in', 15)
100-
self._browser.find_element_by_link_text('Sign in').click()
97+
self._browser.wait_until_visible(By.LINK_TEXT, 'Sign in', 15)
98+
self._browser.click_element(By.LINK_TEXT, 'Sign in')
10199
logging.info(msg='Clicked sign-in prompt')
102100
time.sleep(4)
103101

104102
def _log_into_bing_pc(self):
105103
self._browser.get(BING_SEARCH_URL)
106104
self._browser.wait_until_clickable(By.ID, 'id_l', 5)
107-
self._browser.click_by_id('id_l')
105+
self._browser.click_element(By.ID, 'id_l')
108106
time.sleep(0.1)
109107
self._browser.wait_until_clickable(By.ID, 'id_l', 5)
110-
# self._browser.wait_until_clickable(
111-
# By.XPATH, "//*[text()='Sign in' and @aria-hidden='false']//parent::a", 5)
112-
# if self._browser.find_by_xpath("//*[text()='Sign in' and @aria-hidden='false']//parent::a"):
113-
# self._browser.click_by_xpath(
114-
# "//*[text()='Sign in' and @aria-hidden='false']//parent::a")
115-
# self._browser.wait_until_clickable(
116-
# By.XPATH, "//*[text()='Sign in']//parent::a", 5)
117108

118109
def _log_into_bing_mobile(self):
119110
self._browser.get(BING_SEARCH_URL)
120-
self._browser.wait_until_clickable(
121-
By.XPATH, '//*[@aria-label="Preferences"]', 5)
122-
self._browser.click_by_xpath('//*[@aria-label="Preferences"]')
111+
self._browser.wait_until_clickable(By.XPATH, '//*[@aria-label="Preferences"]', 10)
112+
self._browser.click_element(By.XPATH, '//*[@aria-label="Preferences"]')
123113
time.sleep(0.1)
124-
self._browser.wait_until_clickable(
125-
By.XPATH, "//*[text()='Sign in']//parent::a", 5)
126-
if self._browser.find_by_xpath("//*[text()='Sign in']//parent::a"):
127-
self._browser.click_by_xpath("//*[text()='Sign in']//parent::a")
128-
self._browser.wait_until_clickable(
129-
By.XPATH, '//*[@aria-label="Preferences"]', 5)
114+
self._browser.wait_until_clickable(By.XPATH, "//*[text()='Sign in']//parent::a", 5)
115+
if self._browser.click_element(By.XPATH, "//*[text()='Sign in']//parent::a", ignore_no_ele_exc=True):
116+
self._browser.wait_until_clickable(By.XPATH, '//*[@aria-label="Preferences"]', 5)
130117
else:
131-
self._browser.click_by_xpath('//*[@aria-label="Preferences"]')
118+
self._browser.click_element(By.XPATH, '//*[@aria-label="Preferences"]')
132119

133120
def _accept_bnp(self):
134-
btn = self._browser.find_elements_by_class_name('bnp_btn_accept')
135-
if not btn:
136-
return
137-
btn[0].click()
121+
self._browser.click_element(By.CLASS_NAME, 'bnp_btn_accept', ignore_no_ele_exc=True)
138122

139123
def _click_i_look_good(self):
140-
btn = self._browser.find_elements_by_id('iLooksGood')
141-
if not btn:
142-
return
143-
btn[0].click()
124+
self._browser.click_element(By.ID, 'iLooksGood', ignore_no_ele_exc=True)

msreward/account/stats.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import re
55
import datetime
66

7+
from selenium.webdriver.common.by import By
8+
79
from helper.browser import Browser
810

911

@@ -86,21 +88,21 @@ def get_summary(self, cached=False, log=False):
8688
self._browser.open_in_new_tab(DASHBOARD_URL)
8789
time.sleep(1)
8890

89-
if self._browser.click_by_xpath('//a[contains(@class, "signup-btn welcome")]'):
91+
if self._browser.click_element(By.XPATH, '//a[contains(@class, "signup-btn welcome")]', ignore_no_ele_exc=True):
9092
logging.debug('Welcome page detected.')
9193
time.sleep(4)
9294

9395
self.summary = MSRStatsSummary()
9496
self._parse_user_status(self._get_user_status_json())
9597

96-
self._browser.goto_main_window()
98+
self._browser.goto_main_window_close_others()
9799

98100
if log:
99101
self.summary.print()
100102
return self.summary
101103

102104
def _get_user_status_json(self):
103-
js = self._browser.find_elements_by_xpath(
105+
js = self._browser.find_elements(By.XPATH,
104106
'//script[text()[contains(., "userStatus")]]')
105107
if not js:
106108
return {}

msreward/worker/dashboard/dashboard.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def do_dashboard(self, max_attempts=5):
3737
self._browser.get(DASHBOARD_URL)
3838
time.sleep(0.1)
3939
self._browser.wait_until_visible(By.TAG_NAME, 'body', 10) # checks for page load
40-
open_offers = self._browser.find_elements_by_xpath(
40+
open_offers = self._browser.find_elements(By.XPATH,
4141
'//span[contains(@class, "mee-icon-AddMedium")]')
4242
logging.info(
4343
msg=f'Max attempt reached. Number of incomplete offers: {len(open_offers)}')
@@ -63,21 +63,21 @@ def _goto_offer_link(self, link):
6363
def _goto_dashboard_get_offer_links(self) -> list[WebElement]:
6464
self._browser.get(DASHBOARD_URL)
6565
time.sleep(4)
66-
open_offers = self._browser.find_elements_by_xpath('//span[contains(@class, "mee-icon-AddMedium")]/ancestor::div[contains(@data-bi-id, "Default")]')
66+
open_offers = self._browser.find_elements(By.XPATH, '//span[contains(@class, "mee-icon-AddMedium")]/ancestor::div[contains(@data-bi-id, "Default")]')
6767
logging.info(msg=f'Number of open offers: {len(open_offers)}')
6868
if not open_offers:
6969
return []
7070
return [
71-
offer.find_element_by_tag_name('a')
71+
offer.find_element(By.TAG_NAME, 'a')
7272
for offer in open_offers
7373
]
7474

7575
def _complete_sign_in_prompt(self):
76-
sign_in_prompt_msg = self._browser.find_by_class('simpleSignIn')
76+
sign_in_prompt_msg = self._browser.find_elements(By.CLASS_NAME, 'simpleSignIn')
7777
if not sign_in_prompt_msg:
7878
return
7979
logging.info(msg='Detected sign-in prompt')
8080
self._browser.wait_until_clickable(By.LINK_TEXT, 'Sign in', 15)
81-
self._browser.find_element_by_link_text('Sign in').click()
81+
self._browser.click_element(By.LINK_TEXT, 'Sign in')
8282
logging.info(msg='Clicked sign-in prompt')
8383
time.sleep(4)

msreward/worker/dashboard/linkquest.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22

33
from selenium.common.exceptions import ElementClickInterceptedException, ElementNotInteractableException, ElementNotVisibleException, TimeoutException, WebDriverException
4+
from selenium.webdriver.common.by import By
45
from selenium.webdriver.common.keys import Keys
56

67
from helper.browser import Browser
@@ -10,13 +11,13 @@ class MSRLinkQuest:
1011

1112
def do_link_quest(self):
1213
try:
13-
html = self._browser.find_element_by_tag_name('html')
14+
html = self._browser.find_element(By.TAG_NAME, 'html')
1415
# scroll up and down to trigger points
1516
for _ in range(3):
1617
html.send_keys(Keys.END)
1718
html.send_keys(Keys.HOME)
1819
logging.info('Link Quest completed')
19-
self._browser.goto_main_window()
20+
self._browser.goto_main_window_close_others()
2021
except TimeoutException:
2122
logging.exception(msg='Explore Daily Timeout Exception.')
2223
except (ElementNotVisibleException, ElementClickInterceptedException, ElementNotInteractableException):

msreward/worker/dashboard/punchcard.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import logging
22
import time
33

4-
from selenium.common.exceptions import ElementClickInterceptedException, ElementNotInteractableException, ElementNotVisibleException, NoSuchElementException, TimeoutException, WebDriverException
4+
from selenium.common.exceptions import ElementClickInterceptedException, ElementNotInteractableException, ElementNotVisibleException, TimeoutException, WebDriverException
5+
from selenium.webdriver.common.by import By
56

67
from helper.browser import Browser
78

@@ -22,16 +23,16 @@ def do_punch_card(self, link, max_attempts=3):
2223
finally:
2324
if self._verify_punch_card_completion():
2425
logging.info(msg='Punch Card is completed')
25-
self._browser.goto_main_window()
26+
self._browser.goto_main_window_close_others()
2627
return
2728
logging.debug(msg=f'Punch Card did not complete. Attempt: {i}/{max_attempts}')
28-
self._browser.goto_main_window()
29+
self._browser.goto_main_window_close_others()
2930
logging.info(msg='Punch Card is incomplete. Max number of attempts reached.')
3031

3132
def _click_through_punch_card(self, max_attempts=10):
3233
for _ in range(max_attempts):
3334
try:
34-
if not self._browser.click_by_xpath('//a[@class= "offer-cta"]/child::button[contains(@class, "btn-primary")]'):
35+
if not self._browser.click_element(By.XPATH, '//a[@class= "offer-cta"]/child::button[contains(@class, "btn-primary")]'):
3536
break
3637
time.sleep(1)
3738
self._browser.goto_latest_window()
@@ -42,6 +43,6 @@ def _click_through_punch_card(self, max_attempts=10):
4243
logging.exception(msg='Error occurred when clicking a punch card.')
4344

4445
def _verify_punch_card_completion(self):
45-
return not self._browser.find_by_xpath('//a[@class= "offer-cta" and ./button[contains(@class, "btn-primary")]]')
46+
return not self._browser.find_elements(By.XPATH, '//a[@class= "offer-cta" and ./button[contains(@class, "btn-primary")]]')
4647

4748

msreward/worker/dashboard/quiz/click.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,19 @@ def __init__(self, browser):
1212

1313
def _do_quiz(self):
1414
while True:
15-
if self._browser.find_by_css('.cico.btCloseBack'):
16-
self._browser.find_by_css('.cico.btCloseBack')[0].click()[0].click()
15+
if self._browser.find_elements(By.CSS_SELECTOR, '.cico.btCloseBack'):
16+
self._browser.find_elements(By.CSS_SELECTOR, '.cico.btCloseBack')[0].click()[0].click()
1717
logging.debug(msg='Quiz popped up during a click quiz...')
18-
choices = self._browser.find_by_class('wk_Circle')
18+
choices = self._browser.find_elements(By.CLASS_NAME, 'wk_Circle')
1919
# click answer
2020
if choices:
2121
random.choice(choices).click()
2222
time.sleep(3)
2323
# click the 'next question' button
24-
# wait_until_clickable(By.ID, 'check', 10)
2524
self._browser.wait_until_clickable(By.CLASS_NAME, 'wk_button', 10)
26-
# click_by_id('check')
27-
self._browser.click_by_class('wk_button')
25+
self._browser.click_element(By.CLASS_NAME, 'wk_button')
2826
# if the green check mark reward icon is visible, end loop
2927
time.sleep(1)
30-
if self._browser.find_by_css('span[class="rw_icon"]'):
28+
if self._browser.find_elements(By.CSS_SELECTOR, 'span[class="rw_icon"]'):
3129
break
3230
self._close_quiz_comletion_splash()

msreward/worker/dashboard/quiz/dragdrop.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def __init__(self, browser):
1515

1616
def _do_quiz(self):
1717
for _ in range(100):
18-
if self._browser.find_by_id('quizCompleteContainer'):
18+
if self._browser.find_elements(By.ID, 'quizCompleteContainer'):
1919
break
2020
drag_options = self._get_options_for_drag_drop()
2121
if not drag_options:
@@ -33,8 +33,8 @@ def _do_quiz(self):
3333
self._close_quiz_comletion_splash()
3434

3535
def _get_options_for_drag_drop(self):
36-
drag_options = self._browser.find_by_class('rqOption')
37-
right_answers = self._browser.find_by_class('correctAnswer')
36+
drag_options = self._browser.find_elements(By.CLASS_NAME, 'rqOption')
37+
right_answers = self._browser.find_elements(By.CLASS_NAME, 'correctAnswer')
3838
if right_answers:
3939
drag_options = [x for x in drag_options if x not in right_answers]
4040
return drag_options

msreward/worker/dashboard/quiz/lightning.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ def __init__(self, browser):
1313
def _do_quiz(self):
1414
for question_round in range(10):
1515
logging.debug(msg=f'Round# {question_round}')
16-
if self._browser.find_by_id('rqAnswerOption0'):
16+
if self._browser.find_elements(By.ID, 'rqAnswerOption0'):
1717
time.sleep(3)
1818
for i in range(10):
19-
if self._browser.find_by_id(f'rqAnswerOption{i}'):
19+
if self._browser.find_elements(By.ID, f'rqAnswerOption{i}'):
2020
self._browser.execute_script(
2121
f"document.querySelectorAll('#rqAnswerOption{i}').forEach(el=>el.click());")
2222
logging.debug(msg=f'Clicked {i}')
2323
time.sleep(2)
2424
# let new page load
2525
time.sleep(1)
26-
if self._browser.find_by_id('quizCompleteContainer'):
26+
if self._browser.find_elements(By.ID, 'quizCompleteContainer'):
2727
break
2828
self._close_quiz_comletion_splash()

0 commit comments

Comments
 (0)