【问题标题】:Phantomjs does not execute function in page.evaluate functionPhantomjs 不执行 page.evaluate 函数中的函数
【发布时间】:2012-09-15 07:59:03
【问题描述】:

我正在使用 PhantomJS 节点模块 (https://github.com/sgentle/phantomjs-node) 抓取 Facebook 页面,但是当我尝试评估该页面时,它不会评估我传递给它的函数。在独立脚本中执行它并使用 Node 解释器运行它可以工作。Express.js 应用程序中的相同代码不起作用。

这是我的代码

facebookScraper.prototype.scrapeFeed = function (url, cb) {
    f = ':scrapeFeed:';

    var evaluator = function (s) {
        var posts = [];

        for (var i = 0; i < FEED_ITEMS; i++) {
            log.info(__filename+f+' iterating step ' + i);
            log.info(__filename+f+util.inspect(document, false, null));
        }

        return {
            news: posts
        };
    }

    phantom.create(function (ph) {
        ph.createPage(function (page) {
            log.fine(__filename+f+' opening url ' + url);
            page.open(url, function (status) {
                log.fine(__filename+f+' opened site? ' + status);
                setTimeout(function() {
                    page.evaluate(evaluator, function (result) {
                        log.info(__filename+f+'Scraped feed: ' + util.inspect(result, false, null));
                        cb(result, ph);
                    });
                }, 5000);
            });
        });
    });
};

我得到的输出:

{"level":"fine","message":"PATH/fb_regular.js:scrapeFeed: opening url <URL> ","timestamp":"2012-09-23T18:35:10.151Z"}
{"level":"fine","message":"PATH/fb_regular.js:scrapeFeed: opened site? success","timestamp":"2012-09-23T18:35:12.682Z"}
{"level":"info","message":"PATH/fb_regular.js:scrapeFeed: Scraped feed: null","timestamp":"2012-09-23T18:35:12.687Z"}

因此,如您所见,它使用空参数调用幻像回调函数(评估函数中的第二个参数),但它不执行第一个参数(我的评估器函数,它打印迭代步骤 X)。

谁知道问题出在哪里?

【问题讨论】:

    标签: javascript node.js phantomjs


    【解决方案1】:

    我不确定您使用的是哪个版本的 PhantomJS,但是对于 1.6+ 版本的文档,在评估脚本中记录会将结果记录在包含的页面中。它不会登录到您的控制台。为此,您必须将日志记录绑定到页面 onConsoleMessage 事件:

      page.onConsoleMessage = function (msg) { console.log(msg); };
    

    至于结果不可用: page.evaluate 函数接受这样的参数 - 第一个是要执行的函数,其余的作为输入传递给该函数。结果直接返回:

     var title = page.evaluate(function (s) {
        return document.querySelector(s).innerText;
     }, 'title');
     console.log(title);
    

    【讨论】:

      【解决方案2】:

      evaluate 在沙盒模式下运行,这意味着包含环境中定义的所有变量都不可用,包括 cb 甚至 phantom 对象或您可能定义的任何函数。

      您可以将信息作为evaluate 的附加参数显式传输到沙箱中。

      page.evaluate(function(cb){...},  cb); 
      

      【讨论】:

        【解决方案3】:

        PhantomJS 的page.evaluate() 函数是通往 DOM 上下文(页面上下文)的大门。只能通过此函数访问 DOM。由于该函数是沙盒化的,因此您不能使用在其外部定义的变量,它们必须显式传递。但是,可以传入和传出的内容是有限制的 (docs):

        注意:evaluate 函数的参数和返回值必须是简单的原始对象。经验法则:如果可以通过 JSON 序列化就可以了。

        闭包、函数、DOM 节点等将起作用!

        phantomjs-node 是 PhantomJS 和 node.js 之间的桥梁,因此其 API 与 PhantomJS 本身略有不同。在 PhantomJS 中同步的函数不会在 phantomjs-node 中返回任何内容,而是在传入结果的地方进行回调。回调在外部上下文中执行并且不被沙盒化。

        参数可以这样传递:

        page.evaluate(function(arg1, arg2){
            // use arg1 and arg2 in the page
            // return `result`
        }, function(result){
            // use `result` in the node context
        }, "some arg1", "another arg");
        

        【讨论】:

        • 最新版本的 phantomjs-node 桥应该返回一个 Promise 而不是依赖回调函数。
        • 好吧,我在 evaluate 函数中尝试一些东西会浪费大约 6 个小时...如果它里面有另一个函数,或者任何非原始类型,它甚至不会启动函数执行。 .. 一件重要的事情。 别忘了阅读文档
        【解决方案4】:

        以下内容对我评估页面有用:

        page.evaluate(function(s) {
          return document.querySelector(s)
        }, 'body').then(res => {
          console.log(res)
        })
        

        【讨论】:

          【解决方案5】:

          有人有一个评估块,里面只有一个 console.log 行,它从不执行,它并不总是沙盒问题。

          查看链接:On PhantomJS I can't include jQuery and without jQuery I can't post form data

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-04-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-10-20
            • 1970-01-01
            • 2016-04-11
            • 1970-01-01
            相关资源
            最近更新 更多