mirror of
https://github.com/User0332/rewards-farmer.git
synced 2026-09-16 01:31:36 +00:00
Merge pull request #24 from mardausdennis/fix/wheel-scroll-misc-cards
drive the misc cards scrolling with wheel input instead of fixed bursts
This commit is contained in:
@@ -311,6 +311,57 @@ class MouseUtils:
|
|||||||
self.driver.execute_script(f"window.moveVisualCursor({point[0]}, {point[1]});")
|
self.driver.execute_script(f"window.moveVisualCursor({point[0]}, {point[1]});")
|
||||||
|
|
||||||
|
|
||||||
|
def wheel_scroll_element_into_view(self, element: WebElement, max_wheel_events: int = 60):
|
||||||
|
"""Scroll the element into the viewport with simulated wheel input.
|
||||||
|
|
||||||
|
Wheel steps of varying size with short pauses, the way a person scrolls,
|
||||||
|
instead of a fixed-size burst. The loop is bounded on purpose: an element
|
||||||
|
that never fits the viewport completely, for example one taller than the
|
||||||
|
window, must not hang the run forever. When the budget runs out the
|
||||||
|
caller proceeds with the element as visible as it got.
|
||||||
|
"""
|
||||||
|
for _ in range(max_wheel_events):
|
||||||
|
top, bottom, height = self.driver.execute_script(
|
||||||
|
"var r = arguments[0].getBoundingClientRect();"
|
||||||
|
"return [r.top, r.bottom, window.innerHeight];",
|
||||||
|
element
|
||||||
|
)
|
||||||
|
|
||||||
|
if top >= 0 and bottom <= height:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Aim the element at the middle of the viewport, one notch at a time.
|
||||||
|
distance = (top + bottom) / 2 - height / 2
|
||||||
|
step = max(-320, min(320, distance))
|
||||||
|
step = int(step * random.uniform(0.6, 1.0))
|
||||||
|
|
||||||
|
if abs(step) < 40:
|
||||||
|
step = 40 if distance > 0 else -40
|
||||||
|
|
||||||
|
ActionChains(self.driver).scroll_by_amount(0, step).perform()
|
||||||
|
|
||||||
|
time.sleep(random.uniform(0.04, 0.12))
|
||||||
|
|
||||||
|
def wheel_scroll_to_top(self, max_wheel_events: int = 80):
|
||||||
|
"""Scroll back to the top of the page with simulated wheel input.
|
||||||
|
|
||||||
|
Reads the actual scroll position instead of unwinding a counted number
|
||||||
|
of steps, because the page height can change while cards update and a
|
||||||
|
symmetric unwind then lands in the wrong place.
|
||||||
|
"""
|
||||||
|
for _ in range(max_wheel_events):
|
||||||
|
offset = self.driver.execute_script("return window.scrollY || window.pageYOffset;")
|
||||||
|
|
||||||
|
if offset <= 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
step = min(340, int(offset))
|
||||||
|
step = max(60, int(step * random.uniform(0.6, 1.0)))
|
||||||
|
|
||||||
|
ActionChains(self.driver).scroll_by_amount(0, -step).perform()
|
||||||
|
|
||||||
|
time.sleep(random.uniform(0.04, 0.12))
|
||||||
|
|
||||||
def move_to_element(self, element: WebElement, visualize: bool=True):
|
def move_to_element(self, element: WebElement, visualize: bool=True):
|
||||||
# The pointer is moved to viewport coordinates, so an element below the
|
# The pointer is moved to viewport coordinates, so an element below the
|
||||||
# fold yields a target outside the window and the driver rejects the move
|
# fold yields a target outside the window and the driver rejects the move
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ from selenium.webdriver.common.by import By
|
|||||||
from selenium.webdriver.support.ui import WebDriverWait
|
from selenium.webdriver.support.ui import WebDriverWait
|
||||||
from selenium.webdriver.common.keys import Keys
|
from selenium.webdriver.common.keys import Keys
|
||||||
from selenium.webdriver.remote.webelement import WebElement
|
from selenium.webdriver.remote.webelement import WebElement
|
||||||
from selenium.webdriver.common.action_chains import ActionChains
|
|
||||||
from selenium.common.exceptions import StaleElementReferenceException, TimeoutException, NoSuchElementException
|
from selenium.common.exceptions import StaleElementReferenceException, TimeoutException, NoSuchElementException
|
||||||
import tab_utils
|
import tab_utils
|
||||||
import llm_utils
|
import llm_utils
|
||||||
@@ -140,12 +139,8 @@ class RewardsTaskUtils:
|
|||||||
|
|
||||||
misc_cards: list[WebElement] = self.wait_for_element(self.elements.get_all_misc_cards)
|
misc_cards: list[WebElement] = self.wait_for_element(self.elements.get_all_misc_cards)
|
||||||
|
|
||||||
scroll_times = 0
|
|
||||||
|
|
||||||
for card in misc_cards:
|
for card in misc_cards:
|
||||||
while not self.elements.element_is_fully_in_viewport(card): # this should work for top-down iteration
|
self.mouse.wheel_scroll_element_into_view(card)
|
||||||
ActionChains(self.driver).scroll_by_amount(0, 100).perform()
|
|
||||||
scroll_times+=1
|
|
||||||
|
|
||||||
if not self.elements.card_is_complete(card) and self.elements.get_card_point_value(card) > 0:
|
if not self.elements.card_is_complete(card) and self.elements.get_card_point_value(card) > 0:
|
||||||
self.move_to_and_click(card)
|
self.move_to_and_click(card)
|
||||||
@@ -158,8 +153,7 @@ class RewardsTaskUtils:
|
|||||||
|
|
||||||
self.tab_utils.close_all_other_tabs()
|
self.tab_utils.close_all_other_tabs()
|
||||||
|
|
||||||
for i in range(scroll_times):
|
self.mouse.wheel_scroll_to_top()
|
||||||
ActionChains(self.driver).scroll_by_amount(0, -100).perform() # scroll back to top of page
|
|
||||||
|
|
||||||
def complete_required_searches(self, max_rounds: int = 6):
|
def complete_required_searches(self, max_rounds: int = 6):
|
||||||
# Points per search are not fixed. Some markets award 3 rather than 5,
|
# Points per search are not fixed. Some markets award 3 rather than 5,
|
||||||
|
|||||||
Reference in New Issue
Block a user