我有一些我在casperJS中调用的javascript代码,它很短,所以我已经包含了整个列表
var links = [];
var casper = require('casper').create();
function getLinks() {
var links = document.querySelectorAll('table');
return Array.prototype.map.call(links, function(e) {
return e.getAttribute('id');
});
}
casper.start('example.html', function() {
links = this.evaluate(getLinks);
});
casper.run(function() {
this.echo(links.length + ' links found:');
this.echo(' - ' + links.join('\n - ')).exit();
});
这会输出预期的
3 links found:
- table A
- table B
- table C
切换到getLinks中的匿名函数,以便用以下两个函数替换getLinks
function extract(e) {
return e.getAttribute('id');
}
function getLinks() {
var links = document.querySelectorAll('table');
return Array.prototype.map.call(links, extract);
}
产量
TypeError: 'null' is not an object (evaluating 'links.length')
/Users/jrrpl/git/gamecock/download.js:18
/usr/local/Cellar/casperjs/1.1-beta3/libexec/modules/casper.js:408 in checkStep
更新
似乎对命名函数的引用导致casper.run()提前执行。有人知道为什么会这样吗?
答案 0 :(得分:2)
问题在于this.evaluate(getLinks);
。 The docs state:
基本上PhantomJS’ WebPage#evaluate等效。
了解evaluate()
这种方法背后的概念可能是最难的 在发现CasperJS时了解。提醒一下,想一想 evaluate()方法作为CasperJS环境和之间的门 你打开的一个页面;每次你把关闭传递给 evaluate(),您正在进入页面并执行代码,就像您一样 使用浏览器控制台。
即使PhantomJS文档也没有声明(更重要的是?我是否错过了?)究竟发生了什么。 The source code虽然非常明确:
page.evaluate = function (func, args) { var str, arg, argType, i, l; if (!(func instanceof Function || typeof func === 'string' || func instanceof String)) { throw "Wrong use of WebPage#evaluate"; } str = 'function() { return (' + func.toString() + ')('; for (i = 1, l = arguments.length; i < l; i++) { … str += JSON.stringify(arg) + ","; … } str = str.replace(/,$/, '') + '); }'; return this.evaluateJavaScript(str); };
不,我们也明白为什么要求函数的所有参数都需要序列化:整个事物被转换为一个代码字符串,然后在页面中注入 - &#34;执行就像它被粘贴到控制台&#34;。
这意味着关闭不起作用,最终您将在页面中未定义extract
。如果你确实使用了
function getLinks() {
function extract(e) {
return e.getAttribute('id');
}
var links = document.querySelectorAll('table');
return Array.prototype.map.call(links, extract);
}
然后它应该工作。