javascript Phantom.js 中的 setTimeout

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28950627/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 09:49:10  来源:igfitidea点击:

setTimeout in Phantom.js

javascriptnode.jsmeteorphantomjs

提问by Nyxynyx

The code below wants Phantom.js to load the page, click on a button and wait for 5 seconds before returning the page's HTML code.

下面的代码希望 Phantom.js 加载页面,单击按钮并等待 5 秒钟,然后返回页面的 HTML 代码。

Problem:However using setTimeout()to create the 5 seconds delay causes the page.evaluatefunction to return nullto the callback function instead of the HTML.

问题:但是使用setTimeout()来创建 5 秒延迟会导致 page.evaluate函数返回null到回调函数而不是 HTML。

myUrl = 'http://www.google.com'

var phantom = Meteor.npmRequire('phantom')
phantom.create = Meteor.wrapAsync(phantom.create)
phantom.create( function(ph) {

    ph.createPage = Meteor.wrapAsync(ph.createPage)
    ph.createPage(function(page) {

        page.open = Meteor.wrapAsync(page.open)
        page.open(listingUrl, function(status) {
            console.log('Page loaded')

            page.evaluate = Meteor.wrapAsync(page.evaluate)
            page.evaluate(function() {

                // Find the button
                var element = document.querySelector( '.search-btn' );

                // create a mouse click event
                var event = document.createEvent( 'MouseEvents' );
                event.initMouseEvent( 'click', true, true, window, 1, 0, 0 );

                // send click to element
                element.dispatchEvent( event );

                // Give page time to process Click event
                setTimeout(function() {
                    // Return HTML code
                    return document.documentElement.outerHTML
                }, 5000)

            }, function(html) {

                // html is `null`
                doSomething()

            })
        })
    })
})

Replacing setTimeout()with Meteor.setTimeout()causes another error:

替换setTimeout()Meteor.setTimeout()导致另一个错误:

phantom stdout: ReferenceError: Can't find variable: Meteor

采纳答案by Artjom B.

page.evaluate()is the sandboxed page context of PhantomJS. It has no access to variables defined on the outside. If you need the timeout, then you need to do two calls to page.evaluate(), because you cannot return anything from a asynchronous function (explanation):

page.evaluate()是 PhantomJS 的沙盒页面上下文。它无法访问外部定义的变量。如果您需要超时,那么您需要对 进行两次调用page.evaluate(),因为您无法从异步函数(解释)返回任何内容:

page.evaluate(function() {
    ...
    element.dispatchEvent( event );
}, function() {
    setTimeout(function() {
        page.evaluate(function() {    
            return document.documentElement.outerHTML
        }, function(html) {
            doSomething()
        })
    }, 5000)
})

Instead of using the second page.evaluate()call, you may shorten the code by directly accessing the content as defined here:

page.evaluate()您可以通过直接访问此处定义的内容来缩短代码,而不是使用第二个调用:

setTimeout(function() {
    page.get("content", function(content) {
        doSomething()
    })
}, 5000)

回答by user3596375

This is not a great solution but works if all you want to do is handle page changes on button clicks and form submits. Just declare the function variables outside page.open() and then assign them page evaluation functions later inside. onLoadFinished will be called after the page has reloaded with changes from the button click and then you can evaluate it again.

这不是一个很好的解决方案,但如果您想要做的只是处理按钮点击和表单提交时的页面更改,那么它是有效的。只需在 page.open() 外部声明函数变量,然后在内部分配页面评估函数即可。onLoadFinished 将在页面重新加载并通过单击按钮进行更改后调用,然后您可以再次对其进行评估。

var loadInProgress = false,
jurl = 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js',
page = require('webpage').create();

// declare variables outside page.open and assign them later inside
var evalPageFunc;

// assign callbacks which will be called by phantom
page.onLoadStarted = function() {
    loadInProgress = true;
    console.log('load started');
};
page.onLoadFinished = function() {
    loadInProgress = false;
    console.log('load finished');
    if (evalPageFunc) {
      // since the page has loaded we can safely evaluate it
      var mydata = evalPageFunc();
      console.log(mydata);
      if (!mydata.havemore) {
        phantom.exit();
        // or next url
      }
    }
};

page.open(url, function(status) {
  page.includeJs(jurl, function(){

    // define your page evaluating functions
    evalPageFunc = function(){
      return page.evaluate(function() {
        var datafromhtml = {}, havemoretoclick = true;
        // get your data and perform clicks if you want to
        // datafromhtml.somedata = $('stealme').text();
        // $("clickme").click();
        return {
          havemore: havemoretoclick,
          data: datafromhtml
        };
      });
    }
    var k = evalPageFunc();
  });
});

Its not pretty but it works.

它不漂亮,但它有效。