使用Selenium Webdriver滚动时加载AJAX内容

时间:2013-07-10 17:34:37

标签: java javascript ajax selenium-webdriver

我正在使用Selenium WebDriver来获取网站的内容。 (注意:该站点没有API。希望它能。)该站点使用AJAX在用户滚动时动态加载内容。为了获得该内容,我一直在使用Javascript向下滚动,然后尝试使用findElements()来访问内容。

为了清楚设置,页面包含几个嵌套元素,其中一个是带有“GridItems”类的div(没有名称或id)。这个div包含许多具有“Item”类的子元素(同样,没有名称或id,只有类)。我想在div中使用类“Item”获取每个元素。页面首次加载时可以访问大约25个项目(在当前窗口中不一定可见,但在DOM中可用),向下滚动可以加载更多项目。

我的主要问题如下:首先,当我到达底部时,我想停止滚动。但是,我无法弄清楚使用什么停止条件。如何确定何时到达页面底部? Window.scrollheight将不起作用,因为它将给出现有窗口的高度,而不是它添加更多内容后的高度。我曾考虑测试页面底部的元素是否可见/可点击,但如果不是,则可能仅仅因为它尚未加载,而不是因为尚未到达。即使使用Wait也可能不起作用,因为如果它超时,我不知道是不是因为它没有到达底部,或者只是因为它需要很长时间才能加载。

第二个问题是,当我向下滚动时,它会加载更多元素,但最终,向下滚动会从底部加载更多元素并删除顶部的DOM。这意味着我不能只是向下滚动到底部,然后使用findElements()来获取所有项目,因为许多第一个项目将会消失。我知道会有多少项目,所以目前我正在做以下事情:

    int numitems = 135;
    List<WebElement> newitems;
    List<WebElement> allitems = new ArrayList<WebElement>(50);

    do {
        //scroll down the full length of the visible window three times
        for(int i=0; i < 3; i++)
        {
            //scroll down
            js.executeScript("window.scrollTo(0, document.body.offsetHeight)");

        }

        //check how many items are now available
  //if it runs too fast, it may get to the next line before it finishes scrolling;
  //make it wait until the desired div is visible 
    WebElement cont =  (new WebDriverWait(driver, 100))
.until(ExpectedConditions.presenceOfElementLocated(By.className("GridItems")));


       //get all Items in the div
        newitems = cont.findElements(By.className("Item"));


    //add all the items extracted after scrolling 3 times to the list   
        allitems.addAll(newitems);

    //repeat until there are more items in the general list than are expected
    //to be found. This is hacky; I wish there was a better stopping condition
    }while(numitems > allitems.size()); 

也就是说,我滚动页面三次,滚动后获取所有元素,并将它们添加到列表中。我重复这个,直到列表中的元素多于我期望找到的元素。

这个问题在于,由于滚动每次都会向DOM添加不同数量的项目,因此在每次迭代时添加到allitems列表的内容之间通常会有重叠。元素只是具有唯一ID的对象,不包含有关实际HTML的信息,因此我无法检查它们是否重复。如果滚动没有完全重叠,我也可能会丢失一些项目。此外,由于我向下滚动,列表中较早退出顶部的项目失去了与DOM的连接,然后当我尝试处理它时,我得到一个StaleElementReferenceException。

我想,我可以处理每个项目,但我认为它会使代码变得笨拙。这也将允许我检查其实际内容并找到重复项。我不确定这是否会确保我不会跳过任何内容。

有没有人对如何做到这一点有任何建议?我错过了一些非常重要的事情吗?关于AJAX内容加载的其他问题解决了一些不同的问题。 (例如,我通常没有内容没有加载并且必须等待它的问题,尽管我确实包含了等待。)似乎应该有更好的方法来做到这一点 - 是吗?

对不起啰嗦的帖子感到抱歉;我希望很清楚。

非常感谢,  BSG

编辑:

我意识到接受的答案只能回答部分问题。对于其余部分,我发现一次向下滚动一个屏幕并且每次都获得所有新元素意味着我没有失去任何。在每次滚动之后,我加载了所有元素并进行了一些处理以保存每个元素的内容。这引入了很多冗余,我用HashSet来消除。当我到达底部时,我停止滚动,这由接受的答案中的代码确定。希望这会有所帮助。

1 个答案:

答案 0 :(得分:1)

如何确定何时到达页面底部?

JS不能很好地工作,所以我使用jQuery来确定它。一旦我到达底部,评估结果为真:

$(document).height() == ($(window).height() + $(window).scrollTop();

有什么区别他们的独特性吗?您的flickr示例包含图像,通过使用WebElement.getAttribute("src")创建唯一标识符,可以使用图像的URL。