【问题标题】:Getting Selenium WebDriver to Scroll Down in Google Maps Directions Panel让 Selenium WebDriver 在 Google 地图方向面板中向下滚动
【发布时间】:2024-05-01 01:40:03
【问题描述】:

我正在尝试让 Selenium(特别是 WebDriver v2.31)与 Google 地图进行交互。我可以点击 [first] Get Directions 按钮输入一对地址,然后单击两个地址下的 Get Directions 按钮。这导致了一组行驶方向。我不能做的是让 Selenium 滚动到“方向”面板的底部,这样我就可以看到目的地和“保存到我的地图”链接。不知道是不是因为滚动条是浏览器产生的问题。

我可以在 Yahoo! 上进行搜索并滚动到结果网页的底部;我认为这是因为网页架构中没有其他框架或面板。尽管如此,浏览器生成的是滚动条,而不是网页。

我可以用鼠标按住并向下拖动滚动条来构建一个动作。我不喜欢这种解决方案,因为如果页面大小不同或面板大小不同,执行此操作会导致大量重新计算。我更喜欢类似于 Yahoo! 中的单个“文档”窗口的解决方案。或谷歌代码。

任何帮助将不胜感激。在过去的三天里,我一直在互联网上绞尽脑汁寻找解决方案。

谢谢。

史蒂夫

附录: 如下所述。我不是想对地图本身做任何事情,而是对包含方向的面板做任何事情。我正在使用 Google 地图,因为它类似于我稍后必须测试的应用程序。我需要能够让 [Selenium] WebDriver 滚动到面板底部,这样我就可以选择“下一步”链接——就像滚动到 Google 地图中的“方向”面板底部并在底部看到“保存”链接一样。

我不确定我在使用术语面板时是否使用了正确的术语。问题在于,当显示网页时,面板会动态生成滚动条。

driver.switchTo().frame(driver.findElement(By.id("spsizer")));
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("javascript:window.scrollBy(250,750)", element);
driver.switchTo().defaultContent();

不幸的是,“面板”不包含在框架中,或者是一个框架......由 Selenium 返回的异常标识:

 Exception in thread "main" org.openqa.selenium.NoSuchFrameException: Element is not a frame element: DIV

我相信我已经使用 FireBug 确定该面板有一个 ID(“spsizer”)。

这也不起作用:

element = driver.findElement(By.id("spsizer"));
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("javascript:window.scrollBy(250,750)", element);

这只是在不滚动到方向面板底部的情况下执行,但它也不会引发异常。

【问题讨论】:

    标签: selenium webdriver scrollbar


    【解决方案1】:

    我可以保存我的地图链接,下面的屏幕截图中给出了以下代码。

    向下滚动面板无需记录步骤,Selenium 可以在网页中的任何 Web 对象上定位并执行操作,而用户不可见。

    代码详情:

    第6行:Command- waitForVisible Target- //div[@id='dir_sr']/a[@id='srlink']

    我添加了 waitForVisible,这样 Selenium 将等待 5 秒,然后链接 Save to My Maps 才可见。在按下获取路线按钮后,这将为页面加载提供足够的同步时间。 //div[@id='dir_sr']/a[@id='srlink'] 是链接保存到我的地图

    的 XPath 定位器

    第7行:Command-点击Target- //div[@id='dir_sr']/a[@id='srlink']

    点击链接保存到我的地图

    第8行:Command-点击Target- //按钮[@id='srsave']

    点击按钮保存

    C#.Net WebDriver 代码相同。请注意,必须提供 Google 帐户用户名和密码才能保存地图链接。

    using System;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading;
    using NUnit.Framework;
    using OpenQA.Selenium;
    using OpenQA.Selenium.Firefox;
    using OpenQA.Selenium.Support.UI;
    
    namespace SeleniumTests
    {
        public class GoogleMapSavingTest
        {
              static void Main(string[] args)
              {
                  IWebDriver driver = new FirefoxDriver();
                  driver.Navigate().GoToUrl("https://maps.google.com.au/");
                  driver.FindElement(By.Id("d_launch")).Click();
                  driver.FindElement(By.Id("d_d")).Clear();
                  driver.FindElement(By.Id("d_d")).SendKeys("Franklin, ACT");
                  driver.FindElement(By.Id("d_daddr")).Clear();
                  driver.FindElement(By.Id("d_daddr")).SendKeys("Gungahlin, ACT");
                  driver.FindElement(By.Id("d_d")).Click();
                  driver.FindElement(By.Id("d_sub")).Click();
                  for (int second = 0;; second++) 
                  {
                        if (second >= 60) Assert.Fail("timeout");
                         try
                         {
                            if  (driver.FindElement(By.XPath("//div[@id='dir_sr']/a[@id='srlink']")).Displayed) break;
                        }
                        catch (Exception)
                        {}
                        Thread.Sleep(1000);
                    }
                 driver.FindElement(By.XPath("//div[@id='dir_sr']/a[@id='srlink']")).Click();
                    driver.FindElement(By.Id("Email")).SendKeys("UserName");
                    driver.FindElement(By.Id("Passwd")).SendKeys("Password");
                    driver.FindElement(By.Id("signIn")).Click();
                    for (int second = 0; ; second++)
                    {
                        if (second >= 60) Assert.Fail("timeout");
                        try
                        {
                            if (driver.FindElement(By.XPath("//div[@id='dir_sr']/a[@id='srlink']")).Displayed) break;
                        }
                        catch (Exception)
                        { }
                        Thread.Sleep(1000);
                    }
                 driver.FindElement(By.XPath("//div[@id='dir_sr']/a[@id='srlink']")).Click();
                driver.FindElement(By.XPath("//button[@id='srsave']")).Click();
    
    
              }
    
    
    
    
    
    }
    

    }

    【讨论】:

    • 感谢您的建议,但我没有使用 Selenium IDE。当我尝试通过 WebDriver 选择链接时,我收到一个异常,指出链接不可见 [因为我没有滚动到面板底部]。
    • 尝试使用 WebDriver 中的逻辑 - 我已更新的 C#.Net 程序,它可以工作。无需向下滚动 WebDriver 即可识别“保存到我的地图”网络链接。
    • 感谢代码 sn-p。这解决了我的问题(在我必须测试的真实应用程序上)。这是我最终做的事情:if(driver.findElement(By.className("//div[@class='gKN']/a[@class='gwt-Anchor gHN']")).isDisplayed()) driver.findElement(By.className("//div[@class='gKN']/a[@class='gwt-Anchor gHN']")).click(); 但从长远来看,我仍然需要弄清楚如何滚动动态生成的滚动条,因为我可能只需要向下滚动部分面板即可查看某些内容。
    • 很好,我认为应该可以使用 System.Windows.Forms - 类或使用 OpenQA.Selenium.IMouse 类来执行鼠标操作。我会尝试,如果我得到任何结果会告诉你。同时,我认为你应该发布一个关于动态滚动条滚动的新问题。
    【解决方案2】:

    我知道有人在 GitHub 上创建了一个 Selenium 扩展,该扩展旨在用于自动化地图应用程序,但我不记得如何找到它。几周前我在浏览 GitHub 时看到了它,它通过 javascript 使用图像识别(我不是指 Sikuli)。我认为,如果您足够努力地寻找,您正在寻找的东西就会存在。

    如果您使用的是远程网格,我会避免使用 Sikuli,否则它可能对您有用。此外,当涉及 iframe 时,最好在放弃自动执行框架之前始终尝试 JavaScriptExecutor(带有 switchTo 框架)。

    在此之前,您可以先查看 WebDriverJS 。此外,GhostDriver 可能值得一看,即使只是为了获得灵感。

    【讨论】:

    • 感谢您的指导,但我不希望自动化地图功能。我试图让 Selenium WebDriver 确认面板中浏览器生成的滚动条,就像 Selenium 在普通的香草(无面板或框架)网页中所做的那样,该网页的查看窗口内容过多。我选择谷歌地图是因为它的可访问性和受欢迎程度,我本可以找到另一个没有地图但仍然有面板显示信息的网站。
    • 哦,我明白了。这很容易。您需要使用 driver.switchTo().frame( frameId )。当您在切换到该框架时使用 findElement 时,最新版本的 webdriver 将自动滚动(我相信)。
    • 我是否使用正确的术语将该区域称为“面板”[显示转弯行驶方向的位置]?还是那仍然是一个框架?我熟悉框架,但只熟悉那些不显示/隐藏的框架。您能告诉我在 Google 地图页面源代码中哪里可以找到 frameId 吗?最近两天我一直在寻找不同的ID。再次感谢。
    • 我知道 Firebug HTML 选项卡会显示 iframe 的位置(显然 ID 为“vp”)。 “面板”一词与 JavaFX 或 Swing(我认为)相关联,但如果有人决定将组件命名为“面板”,它也可能与网页元素相关联。 Google 地图是 iframe 的一个更困难的示例,因此如果您无法弄清楚,请尝试编写自己的 HTML 页面,并在 iframe 中使用滑块作为示例进行尝试。
    最近更新 更多