如何用Selenium WebDriver(Python)滚动自定义滚动条定位网格元素
Hey Pavel, let's work through this custom scrollbar issue you're facing with your Kendo Grid. The drag-and-drop approach isn't working because your target row is outside the viewport, which triggers that MoveTargetOutOfBoundsException. Instead, we can leverage the existing Kendo Grid JavaScript APIs you mentioned—this will be far more reliable than trying to simulate drag actions.
Option 1: Scroll Directly to the Target Element (Recommended)
Since you already have access to the grid's verticalScrollbar via window.GridProfile_Grid.data("kendoGrid"), we can directly set its scrollTop value to the position of your target row. Here's how to implement this:
- First, locate your target row (even if it's not visible in the viewport, Selenium can still find it as long as it exists in the DOM).
- Use JavaScript to get the row's offset from the top of the grid, then set the scrollbar's position to that offset.
from selenium.webdriver.common.by import By # Locate the 31st row (index 30 in your list) target_row = driver.find_element(By.XPATH, "//tr[@role='row'][31]") # Execute JavaScript to scroll directly to the target row driver.execute_script(""" // Get the Kendo Grid instance const kendoGrid = window.GridProfile_Grid.data("kendoGrid"); // Get the target row's top offset relative to the grid container const targetOffset = arguments[0].offsetTop; // Set the scrollbar's position to this offset kendoGrid.virtualScrollable.verticalScrollbar.scrollTop(targetOffset); // Call the page's scroll state update function to sync any internal state updateGridScrollInState(); """, target_row)
This method jumps straight to the row, no looping required—perfect if you know exactly which row you need.
Option 2: Loop Until the Target Element is Visible
If you need to handle cases where the row might not be loaded yet (common in virtual scrolling grids), you can incrementally scroll and check if the row becomes visible:
from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException target_row = driver.find_element(By.XPATH, "//tr[@role='row'][31]") scroll_step = 200 # Adjust this value based on how much each scroll should move max_attempts = 10 # Prevent infinite loops try: for _ in range(max_attempts): if target_row.is_displayed(): break # Scroll down by the defined step driver.execute_script(""" const kendoGrid = window.GridProfile_Grid.data("kendoGrid"); const currentScroll = kendoGrid.virtualScrollable.verticalScrollbar.scrollTop(); kendoGrid.virtualScrollable.verticalScrollbar.scrollTop(currentScroll + arguments[0]); updateGridScrollInState(); """, scroll_step) # Short wait to let the grid load new rows (adjust as needed) driver.implicitly_wait(0.5) # Final check to ensure the row is visible WebDriverWait(driver, 10).until(EC.visibility_of(target_row)) except TimeoutException: print("Failed to scroll to the target row within the maximum attempts.")
Why Drag-and-Drop Failed
The MoveTargetOutOfBoundsException happens because Selenium's drag_and_drop requires both the source (scrollbar) and target (row) elements to be within the current viewport. Since your target row is outside the viewport, this method can't reach it. Using the grid's native JS APIs avoids this limitation entirely, as we're directly controlling the scrollbar's position rather than simulating mouse movements.
Quick Checks to Verify
Before running the code, open your browser's developer console and confirm:
window.GridProfile_Grid.data("kendoGrid")returns a valid Kendo Grid instanceupdateGridScrollInState()runs without errors (this syncs the scroll state with the grid's internal data)
内容的提问来源于stack exchange,提问作者Pavel

