如何用Phantomjs向下滚动加载动态内容

问题描述 投票:0回答:4

我试图从当用户向下滚动到底部(无限滚动)时动态生成内容的页面中抓取链接。我尝试过使用 Phantomjs 做不同的事情,但无法收集首页之外的链接。假设底部加载内容的元素具有类

.has-more-items
。它一直可用,直到滚动时加载最终内容,然后在 DOM 中变得不可用(display:none)。这是我尝试过的事情-

  • var page = require('webpage').create();
  • 之后立即将 viewportSize 设置为较大高度

page.viewportSize = { 宽度:1600,高度:10000, };

  • page.scrollPosition = { top: 10000, left: 0 }
    内使用
    page.open
    但没有类似-
  • 的效果
page.open('http://example.com/?q=houston', function(status) {
   if (status == "success") {
      page.scrollPosition = { top: 10000, left: 0 };  
   }
});
  • 还尝试将其放入
    page.evaluate
    函数中,但这给出了

引用错误:找不到变量页面

  • 尝试在
    page.evaluate
    page.open
    中使用jQuery和JS代码,但无济于事-

$("html, body").animate({scrollTop: $(document).height() }, 10, 功能() { //console.log('检查执行情况'); });

原样,也在里面

document.ready
。 JS 代码也是如此 -

window.scrollBy(0,10000)

原样,也在里面

window.onload

我已经被这个问题困扰了两天了,但找不到方法。任何帮助或提示将不胜感激。

更新

我在 https://groups.google.com/forum/?fromgroups=#!topic/phantomjs/8LrWRW8ZrA0

找到了一段有用的代码
var hitRockBottom = false; while (!hitRockBottom) {
    // Scroll the page (not sure if this is the best way to do so...)
    page.scrollPosition = { top: page.scrollPosition + 1000, left: 0 };

    // Check if we've hit the bottom
    hitRockBottom = page.evaluate(function() {
        return document.querySelector(".has-more-items") === null;
    }); }

其中

.has-more-items
是我想要访问的元素类,它最初位于页面底部,当我们向下滚动时,它会进一步向下移动,直到所有数据加载完毕,然后变得不可用。

但是,当我测试时,很明显它会在不向下滚动的情况下陷入无限循环(我渲染图片进行检查)。我也尝试用下面的代码替换

page.scrollPosition = { top: page.scrollPosition + 1000, left: 0 };
(一次一个)

window.document.body.scrollTop = '1000';
location.href = ".has-more-items";
page.scrollPosition = { top: page.scrollPosition + 1000, left: 0 };
document.location.href=".has-more-items";

但似乎没有任何效果。

javascript web-scraping dom phantomjs
4个回答
46
投票

找到了一种方法并尝试适应您的情况。我没有测试查找页面底部的最佳方法,因为我有不同的上下文,但请检查下面的解决方案。这里的问题是,您必须等待一段时间才能加载页面,并且 javascript 异步工作,因此您必须使用

setInterval
setTimeout
(see) 来实现此目的。

page.open('http://example.com/?q=houston', function () {

  // Check for the bottom div and scroll down from time to time
  window.setInterval(function() {
      // Check if there is a div with class=".has-more-items" 
      // (not sure if there's a better way of doing this)
      var count = page.content.match(/class=".has-more-items"/g);

      if(count === null) { // Didn't find
        page.evaluate(function() {
          // Scroll to the bottom of page
          window.document.body.scrollTop = document.body.scrollHeight;
        });
      }
      else { // Found
        // Do what you want
        ...
        phantom.exit();
      }
  }, 500); // Number of milliseconds to wait between scrolls

});

4
投票

我知道很久以前就已经回答了,但我也找到了针对我的具体场景的解决方案。结果是一段滚动到页面底部的 JavaScript。它经过优化以减少等待时间。

默认情况下它不是为 PhantomJS 编写的,因此必须进行修改。然而,对于初学者或没有 root 访问权限的人来说,注入 javascript 的 Iframe(使用 --disable-javascript 参数运行 Google Chrome)是抓取较小的 ajax 页面集的一个很好的替代方法。主要好处是它易于调试,因为您可以直观地了解刮刀的运行情况。

function ScrollForAjax () {

    scrollintervals = 50;
    scrollmaxtime = 1000;

    if(typeof(scrolltime)=="undefined"){
        scrolltime = 0;
    }

    scrolldocheight1 = $(iframeselector).contents().find("body").height();

    $("body").scrollTop(scrolldocheight1);
    setTimeout(function(){

        scrolldocheight2 = $("body").height();

        if(scrolltime===scrollmaxtime || scrolltime>scrollmaxtime){
            scrolltime = 0;
            $("body").scrollTop(0);
            ScrapeCurrentPage(iframeselector);
        }

        else if(scrolldocheight2>scrolldocheight1){
            scrolltime = 0;
            ScrollForAjax (iframeselector);
        }

        else if(scrolldocheight1>=scrolldocheight2){
            ScrollForAjax (iframeselector);
        }

    },scrollintervals);

    scrolltime += scrollintervals;
}

scrollmaxtime 是一个超时变量。希望这对某人有用:)


2
投票

“正确”的解决方案对我不起作用。而且,据我所知,CasperJS 不使用

window
(但我可能是错的),这让我怀疑
window
是否有效。

以下内容在 Firefox/Chrome 控制台中适用于我;但是,在 CasperJS 中不起作用(在

casper.evaluate
函数内)。

$(document).scrollTop($(document).height());

CasperJS 对我有用的是:

casper.scrollToBottom();
casper.wait(1000, function waitCb() {
  casper.capture("loadedContent.png");
});

casper.capture
移动到 Casper 的
then
函数中也有效。

但是,上述解决方案在 Twitter 等某些网站上不起作用; jQuery 似乎破坏了

casper.scrollToBottom()
功能,当我在 Twitter 中工作时,我不得不删除对 jQuery 的
clientScripts
引用。

var casper = require('casper').create({
    clientScripts: [
       // 'jquery.js'
    ]
});

一些网站(例如 BoingBoing.net)似乎可以很好地使用 jQuery 和 CasperJS

scrollToBottom()
。不知道为什么有些网站可以运行,而另一些则不能。


1
投票

下面的代码片段对于 pinterest 来说工作得很好。我做了很多研究,在没有 phantomjs 的情况下抓取 pinterest,但不可能找到无限滚动触发链接。我认为下面的代码将有助于其他无限滚动网页的抓取。

page.open(pageUrl).then(function (status) {
    var count = 0;
    // Scrolls to the bottom of page
    function scroll2btm() {
        if (count < 500) {
            page.evaluate(function(limit) {
                window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
                return document.getElementsByClassName('pinWrapper').length; // use desired contents (eg. pin) selector for count presence number
            }).then(function(c) {
                count = c;
                console.log(count); // print no of content found to check
            });
            setTimeout(scroll2btm,3000);
        } else {
            // required number of item found
        }
    }
    scroll2btm();
});
© www.soinside.com 2019 - 2024. All rights reserved.