15

我正在使用 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"}

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

任何人都知道问题是什么?

4

5 回答 5

28

我不确定您使用的是什么版本的 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);
于 2012-09-23T19:36:02.207 回答
10

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

您可以将信息显式隧道传输到沙箱中,作为evaluate.

page.evaluate(function(cb){...},  cb); 
于 2012-11-29T09:46:29.953 回答
5

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

注意:函数的参数和返回值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");
于 2015-07-07T07:33:58.677 回答
2

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

page.evaluate(function(s) {
  return document.querySelector(s)
}, 'body').then(res => {
  console.log(res)
})
于 2017-07-28T16:29:33.850 回答
0

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

查看链接:在 PhantomJS 我不能包含 jQuery,没有 jQuery 我不能发布表单数据

于 2013-04-06T14:48:51.807 回答