Files
rewards-farmer/src/rewards_tasks.py
T

217 lines
7.3 KiB
Python
Raw Normal View History

2026-08-19 14:03:22 -04:00
import os
import random
import time
from typing import Callable
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import StaleElementReferenceException, TimeoutException
2026-08-19 14:03:22 -04:00
import tab_utils
import llm_utils
import mouse_trajectory
import mimic_typing
import element_selectors
2026-08-24 09:19:51 -04:00
VISUAL_SEARCH_IMAGE_PATH = os.path.abspath("keypress_times.png")
2026-08-19 14:03:22 -04:00
class RewardsTaskUtils:
def __init__(self, driver: webdriver.Edge):
self.driver = driver
self.driver.get("https://rewards.bing.com/")
2026-08-19 14:03:22 -04:00
self.tab_utils = tab_utils.TabUtils(driver)
2026-08-20 10:35:35 -04:00
self.tab_utils.ensure_focus()
2026-08-19 14:03:22 -04:00
self.mouse = mouse_trajectory.MouseUtils(driver)
self.keyboard = mimic_typing.KeyboardUtils(driver)
self.elements = element_selectors.ElementSelectionUtils(driver)
def find_element(self, xpath: str):
return self.driver.find_element(By.XPATH, xpath)
def wait_for_element(self, element_getter: Callable[[], WebElement | list[WebElement]], timeout: int = 10) -> WebElement | list[WebElement]:
def condition(_: webdriver.Edge):
try:
element_or_elements = element_getter()
return element_or_elements
except:
return False
return WebDriverWait(self.driver, timeout).until(condition)
def switch_to_earn_page(self):
self.move_to_and_click(self.elements.get_earn_tab())
def switch_to_dashboard(self):
self.move_to_and_click(self.elements.get_dashboard_tab())
def move_to_and_click(self, elem: WebElement):
self.mouse.move_to_element(elem)
self.mouse.human_like_click()
def wait_for_then_click(self, element_getter: Callable[[], WebElement], timeout: int = 10):
elem = self.wait_for_element(element_getter, timeout)
self.move_to_and_click(elem)
def complete_bing_daily_set(self):
self.switch_to_earn_page()
self.wait_for_then_click(self.elements.get_open_daily_set_button)
daily_set_links = self.wait_for_element(self.elements.get_daily_set_elements)
self.move_to_and_click(daily_set_links[0])
time.sleep(random.uniform(2, 3))
self.driver.switch_to.window(self.driver.current_window_handle) # refocus on the main tab
self.move_to_and_click(daily_set_links[1])
time.sleep(random.uniform(2, 3))
self.driver.switch_to.window(self.driver.current_window_handle)
self.move_to_and_click(daily_set_links[2])
time.sleep(random.uniform(2, 3))
self.driver.switch_to.window(self.driver.current_window_handle)
self.tab_utils.close_all_other_tabs()
def complete_explore_on_bing_tasks(self):
self.switch_to_earn_page()
explore_on_bing_links = self.wait_for_element(self.elements.get_explore_on_bing_elements)
for card in explore_on_bing_links:
desc = self.elements.extract_card_descriptions(card)
query = llm_utils.get_search_query_from_task_description(desc)
self.move_to_and_click(card)
self.tab_utils.switch_to_other_tab()
self.wait_for_element(self.elements.get_bing_search_bar)
# search bar should be auto-focused
self.keyboard.send_keys(query+Keys.ENTER)
time.sleep(random.uniform(2, 3))
self.tab_utils.switch_to_other_tab()
self.tab_utils.close_all_other_tabs()
2026-08-20 11:19:35 -04:00
time.sleep(random.uniform(1, 2)) # allow card statuses to update
2026-08-19 14:03:22 -04:00
for card in explore_on_bing_links:
if not self.elements.card_is_complete(card):
2026-08-20 09:28:54 -04:00
print(f"[WARNING] Explore on Bing Card [desc={self.elements.extract_card_descriptions(card)!r}] is not complete after searching. Please check manually.")
2026-08-19 14:03:22 -04:00
def complete_visual_search(self):
self.switch_to_earn_page()
self.wait_for_then_click(self.elements.get_open_visual_search_sidebar)
self.wait_for_then_click(self.elements.get_search_now_link_from_visual_search_sidebar)
self.tab_utils.switch_to_other_tab()
self.wait_for_then_click(self.elements.get_visual_search_button)
file_input = self.wait_for_element(self.elements.get_visual_search_file_input)
2026-08-24 09:19:51 -04:00
file_input.send_keys(VISUAL_SEARCH_IMAGE_PATH)
2026-08-19 14:03:22 -04:00
time.sleep(random.uniform(3, 5))
self.tab_utils.switch_to_other_tab()
self.tab_utils.close_all_other_tabs()
def complete_misc_cards(self):
self.switch_to_earn_page()
misc_cards: list[WebElement] = self.wait_for_element(self.elements.get_all_misc_cards)
2026-08-20 11:19:35 -04:00
scroll_times = 0
2026-08-19 14:03:22 -04:00
for card in misc_cards:
while not self.elements.element_is_fully_in_viewport(card): # this should work for top-down iteration
ActionChains(self.driver).scroll_by_amount(0, 100).perform()
2026-08-20 11:19:35 -04:00
scroll_times+=1
2026-08-19 14:03:22 -04:00
if not self.elements.card_is_complete(card) and self.elements.get_card_point_value(card) > 0:
self.move_to_and_click(card)
time.sleep(random.uniform(1, 2))
self.driver.switch_to.window(self.driver.current_window_handle)
for card in misc_cards:
if not self.elements.card_is_complete(card) and self.elements.get_card_point_value(card) > 0:
2026-08-20 09:28:54 -04:00
print(f"[WARNING] Misc Card [desc={self.elements.extract_card_descriptions(card)!r}] is not complete after clicking. Please check manually.")
2026-08-19 14:03:22 -04:00
self.tab_utils.close_all_other_tabs()
2026-08-20 11:19:35 -04:00
for i in range(scroll_times):
ActionChains(self.driver).scroll_by_amount(0, -100).perform() # scroll back to top of page
2026-08-20 10:29:34 -04:00
def complete_required_searches(self):
self.switch_to_earn_page()
self.wait_for_then_click(self.elements.get_points_breakdown_button)
self.wait_for_element(self.elements.get_close_button_on_points_breakdown) # make sure sidebar loads
points_earned, max_pts = self.elements.get_points_earned_from_searches_on_points_breakdown()
searches_needed = (max_pts - points_earned) // 5
2026-08-19 14:03:22 -04:00
self.driver.get("https://www.bing.com/")
2026-08-20 10:35:35 -04:00
self.tab_utils.ensure_focus()
2026-08-19 14:03:22 -04:00
2026-08-20 10:29:34 -04:00
self.wait_for_element(self.elements.get_bing_search_bar)
2026-08-19 14:03:22 -04:00
# search bar should be auto-focused
2026-08-20 10:29:34 -04:00
for i, query in enumerate(
llm_utils.get_related_search_queries(
llm_utils.get_random_noun(), num_queries=searches_needed
2026-08-20 10:29:34 -04:00
)
2026-08-19 14:03:22 -04:00
):
self.keyboard.send_keys(query+Keys.ENTER)
2026-08-20 10:29:34 -04:00
time.sleep(random.uniform(0.5, 1))
2026-08-19 14:03:22 -04:00
try: self.wait_for_then_click(self.elements.get_clear_bing_search_query_button)
except StaleElementReferenceException:
print(f"[WARNING] StaleElementReferenceException when trying to click the clear button for query {i+1}. Trying again...")
self.wait_for_then_click(self.elements.get_clear_bing_search_query_button)
2026-08-19 14:03:22 -04:00
self.driver.get("https://rewards.bing.com/")
2026-08-20 10:35:35 -04:00
self.tab_utils.ensure_focus()
2026-08-19 14:03:22 -04:00
self.switch_to_earn_page()
self.wait_for_then_click(self.elements.get_points_breakdown_button)
close_btn = self.wait_for_element(self.elements.get_close_button_on_points_breakdown)
points_earned, max_pts = self.elements.get_points_earned_from_searches_on_points_breakdown()
self.move_to_and_click(close_btn)
print(f"Points earned from {searches_needed} searches: {points_earned}/{max_pts}")
2026-08-19 14:03:22 -04:00
def claim_bonus_points(self):
self.switch_to_dashboard()
self.wait_for_then_click(self.elements.get_bonus_button_on_dashboard)
try:
self.wait_for_then_click(self.elements.get_claim_bonus_points_button)
except TimeoutException:
2026-08-19 14:03:22 -04:00
print("[WARNING] Could not find the 'Claim Bonus Points' button. There are likely no bonus points to claim at this time.")
def complete_all_tasks(self):
self.complete_bing_daily_set()
self.complete_explore_on_bing_tasks()
self.complete_visual_search()
self.complete_misc_cards()
2026-08-20 10:29:34 -04:00
self.complete_required_searches()
2026-08-19 14:03:22 -04:00
self.claim_bonus_points()