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

时间:2013-05-15 09:36:58

标签: javascript dom web-scraping screen-scraping phantomjs

我正在尝试从用户向下滚动到底部(无限滚动)动态生成内容的页面中抓取链接。我曾尝试用Phantomjs做不同的事情但不能收集第一页以外的链接。假设加载内容的底部元素具有类.has-more-items。它在滚动期间加载最终内容之前可用,然后在DOM中变为不可用(显示:无)。以下是我尝试过的事情 -

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

page.viewportSize = {width: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.evaluatepage.open中使用jQuery和JS代码,但无济于事 -
  

$(“html,body”)。animate({scrollTop:$(document).height()},10,   function(){           //console.log('check for execution');       });

原样,也在document.ready内。类似的JS代码 -

window.scrollBy(0,10000)

原样,也在window.onload

我现在真的被打了2天,但却找不到办法。任何帮助或提示都将不胜感激。

更新

我在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";

但似乎没有任何效果。

4 个答案:

答案 0 :(得分:45)

找到了一种方法,并尝试适应您的情况。我没有测试找到页面底部的最佳方法,因为我有不同的上下文,但检查出来。问题是您必须稍等一下才能加载页面并且javascript异步工作,因此您必须使用setIntervalsetTimeoutsee)。

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

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

      if(count === null) { // Didn't find
        page.evaluate(function() {
          // Scrolls 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

});

答案 1 :(得分:4)

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

默认情况下不会为PhantomJS编写,因此必须进行修改。但是,对于初学者或没有超级用户权限的人来说,使用注入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 :(得分: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()。不确定为什么有些网站会运作而其他网站不会。

答案 3 :(得分:1)

下面的代码片段适用于pinterest。我研究了很多没有pha​​ntomjs的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();
            })