5

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

为了清楚设置,该页面包含多个嵌套元素,其中之一是具有“GridItems”类(无名称或 ID)的 div。这个 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。

我想我可以在收到每个项目时对其进行处理,尽管这会使代码变得笨拙。这也将允许我检查其实际内容并找到重复项。我不确定这是否能确保我不会跳过任何内容。

有人对如何最好地做到这一点有任何建议吗?我在这里错过了一些非常重要/显而易见的事情吗?SO上关于AJAX内容加载的其他问题解决了一些不同的问题。(例如,虽然我确实包含了等待,但我通常不会遇到内容不加载且必须等待它的问题。)似乎应该有更好的方法来做到这一点 - 有吗?

很抱歉这篇冗长的帖子;我希望这很清楚。

非常感谢,bsg

编辑:

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

4

1 回答 1

1

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

JS 不能很好地解决这个问题,所以我使用 jQuery 来确定。一旦我到达底部,这将评估为真:

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

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

于 2013-07-13T00:39:28.473 回答