如何使用Selenium WebDriver滚动到元素

31

如何使用Selenium WebDriver滚动到特定元素以在屏幕上显示。我尝试了很多不同的选项,但都没有成功。

这在C#绑定中不起作用吗?

我可以使其跳转到特定位置,例如

((IJavaScriptExecutor)Driver).ExecuteScript("window.scrollTo(0, document.body.scrollHeight - 150)");

但我希望能够将其发送到不同的元素,而不需要每次都给出确切的位置。
public IWebElement Example { get { return Driver.FindElement(By.Id("123456")); } }

例1)

((IJavaScriptExecutor)Driver).ExecuteScript("arguments[0].scrollIntoView(true);", Example);

例子2)

((IJavaScriptExecutor)Driver).ExecuteScript("window.scrollBy(Example.Location.X", "Example.Location.Y - 100)");

当我观看它时,它不会跳转到元素所在的页面位置,异常匹配元素已经离开屏幕。
我在它后面添加了一个bool ex = Example.Exists();并检查结果。 它存在(是真的)。 它没有显示(因为它仍然在屏幕外,没有移动到该元素) 它没有被选中????
有人使用By.ClassName看到了成功。 是否有人知道在C#绑定中使用By.Id是否有问题?

也许你可以尝试模拟“箭头向下”按键,直到异常消失。我知道这是一种“不达目的誓不罢休”的方法,但如果你只是想让它以某种方式工作,那么这可能是一个解决方案?! - krizz
你可以尝试一下,使用ExpectedConditions.visibilityOfElement方法,并将其作为while循环的条件,在循环中通过一些坐标(例如100, 100)滚动视图。 - Vivek Singh
在调用 JavaScript 之前,您确定 WebDriver 已经找到了您的元素吗? - Jordan
WebElement已经声明(Driver.FindElement)。我本以为它会像在页面顶部找到所有其他元素一样找到它,并且在到达此元素之前有几个等待。我将测试并再次更新。我想滚动直到找到该元素,因为Selenium Webdriver不允许您对屏幕外的元素执行任何操作。我希望避免任何涉及跳过固定数量的解决方案,因为页面大小会变化。 - merrua
driver.FindElement(By.Id('id-of-ele')).Click()不行吗? - Ray Cheng
12个回答

65
这是一个有些陈旧的问题,但我相信有比上面建议的更好的解决方案。
以下是原始答案:https://dev59.com/kHA75IYBdhLWcg3wPmd8#26461431 您应该使用Actions类来执行滚动到元素的操作。
var element = driver.FindElement(By.id("element-id"));
Actions actions = new Actions(driver);
actions.MoveToElement(element);
actions.Perform();

2
这对我非常有帮助,谢谢。我从来没有真正关注过Actions,但最近出现了几次。我应该真的学习更多关于它们的知识。 - Joel
很棒的答案,我们应该尽可能地依赖其他人深思熟虑过的解决方案。我这么说是因为我已经多次实现了JS hack,并忽略了滚动到元素的默认实现。也就是Actions.MoveToElement。干杯 - Craig Richards

22

这对我在Chrome、IE8和IE11上都有效:

public void ScrollTo(int xPosition = 0, int yPosition = 0)
{
    var js = String.Format("window.scrollTo({0}, {1})", xPosition, yPosition);
    JavaScriptExecutor.ExecuteScript(js);
}

public IWebElement ScrollToView(By selector)
{
    var element = WebDriver.FindElement(selector);
    ScrollToView(element);
    return element;
}

public void ScrollToView(IWebElement element)
{
    if (element.Location.Y > 200)
    {
        ScrollTo(0, element.Location.Y - 100); // Make sure element is in the view but below the top navigation pane
    }

}

1
老兄,你是最棒的! - Denis Koreyba
3
谢谢,这个有效!ScrollTo()函数的C#版本:IJavaScriptExecutor js = (IJavaScriptExecutor)driver; js.ExecuteScript(String.Format("window.scrollTo({0}, {1})", xPosition, yPosition)); (注:该翻译保持了原文的代码格式和语法结构,并根据上下文进行了必要的专业术语翻译。) - medasumanth

15
这对我有效:
var elem = driver.FindElement(By.ClassName("something"));
driver.ExecuteScript("arguments[0].scrollIntoView(true);", elem);

按照 ClassName 进行定位不够唯一,无法满足我的需求。我尝试了上述方法,但对我来说使用 By.Id 无效。你是在暗示问题出在 By.Id 上吗?你是否发现使用 By.ClassName 时会滚动到屏幕外,但使用 By.Id 则不会? - merrua
By.ClassName只是查找元素的示例。您可以使用任何您想要/需要的方法来查找元素。真正的魔法在于滚动到元素,这在JavaScript的scrollIntoView()方法中发生。 如果您难以找到元素,请尝试在此处发布HTML。 - user3734429
1
我刚刚测试了建议的解决方案,它可以正常工作。正如user3734429所说,您不必按类名过滤,您只需要使用WebElement(您可以选择任何一种方式来获取它,按类选择只是其中一种方式)。 - DRAX

3

这对我在C#自动化中有效:

public Page scrollUp()
{
    IWebElement s = driver.FindElement(By.Id("your_locator")); ;
    IJavaScriptExecutor je = (IJavaScriptExecutor)driver;
    je.ExecuteScript("arguments[0].scrollIntoView(false);", s);
    return this;
}

2

我创建了一个IWebDriver的扩展:

最初的回答:

public static IWebElement GetElementAndScrollTo(this IWebDriver driver, By by)
{
    var js = (IJavaScriptExecutor)driver;
    try
    {
        var element = driver.FindElement(by);
        if (element.Location.Y > 200)
        {
            js.ExecuteScript($"window.scrollTo({0}, {element.Location.Y - 200 })");
        }
        return element;
    }
    catch (Exception ex)
    {
        return null;
    }
}

干得好!对我也起作用了!谢谢。 - Konstantin

1
var js = (IJavaScriptExecutor)driver;
js.ExecuteScript("arguments[0].scrollIntoView({behavior: 'smooth', block: 'center'})", PutYourElementIDHere);

0

我正在提供在特定元素中滚动的解决方案,如可滚动表格。

// Driver is the Selenium IWebDriver
IJavaScriptExecutor exec = (IJavaScriptExecutor) Driver;

int horizontalScroll= direction == Direction.Right ? X : 0;
int verticalScroll  = direction == Direction.Down  ? Y : 0;

exec.ExecuteScript(
    "arguments[0].scrollBy(arguments[1], arguments[2])"
  , Self
  , horizontalScroll
  , verticalScroll);

0
                                var e = driver.FindElement(By.XPath("//*[text()='Timesheet']"));
                                // JavaScript Executor to scroll to element
                                ((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView(true);", e);

0
Actions actions = new Actions(driver);
actions.SendKeys(Keys.PageDown).Build().Perform();

你可以通过for循环来实现,它像钟表一样精准可靠,简单易懂,但并不总是方便的。


0

如果我们放置时间是为了让页面加载更长的时间,那么我们就放置它。就这样。

ChromeOptions options = new ChromeOptions();
var driver = new ChromeDriver(options);
driver.Navigate().GoToUrl("https://www.w3schools.com/");
Thread.Sleep(5000);
driver.ExecuteScript("scroll(0,400)");
HtmlDocument countriesDocument = new HtmlDocument();
countriesDocument.LoadHtml(driver.PageSource);

1
仅提供代码的答案并不特别有帮助。请添加一些描述,说明这段代码如何解决问题。 - 4b0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接