我正在编写网站抓取工具,从ajax网站抓取一些特定内容,没有实际链接,只有可点击的文字。我现在只使用javascript大约一个星期,并且正在使用CasperJS,因为它会减少很多工作。
我发现的问题是,我正在编写多个功能,这些功能都做同样的事情,只是根据它所在的页面搜索不同的链接。 所以我有:
function getLinks() {
var links = document.querySelectorAll('div.AjaxLink h3');
return Array.prototype.map.call(links, function(link) {
return link.innerText;
});
}
通过以下方式运行:
casper.then(function() {
var myLinks = this.evaulate(getLinks);
/* ... link manipulation code code ... */
});
这很好用。我显然不想拥有六个只有不同查询字符串的函数。所以我想做的是:
function getLinks(findText) {
var links = document.querySelectorAll(findText);
return Array.prototype.map.call(links, function(link) {
return link.innerText;
});
}
然后我试图通过以下方式运行它:
casper.then(function() {
var myLinks = getLinks('div.AjaxLink h3');
/* ... link manipulation code code ... */
});
正确传入了findText变量,但看起来查询选择器总是返回一个空的NodeList。
我做错了什么? 文档 是在该函数中创建的空文档吗?
答案 0 :(得分:6)
CasperJS建立在PhantomJS之上。 PhantomJS有两种情境。可通过evaluate()
访问的沙盒页面上下文以及可访问require
和phantom
的外部上下文。奇怪的是,两个上下文都可以访问window
和document
,但document
并不意味着外部上下文中的任何内容,因为DOM是空的。这就是querySelectorAll()
找不到元素的原因。页面DOM只能通过evaluate()
访问。
所以你需要在casper.evaluate()
中执行你的功能。函数的附加参数传递给evaluate()
而不是函数:
function getLinks(findText) {
...
}
casper.then(function() {
var myLinks = this.evaluate(getLinks, 'div.AjaxLink h3'); // THIS
...
});
evaluate
页面底部还有一个重要提示:
注意:
evaluate
函数的参数和返回值必须是一个简单的原始对象。经验法则:如果它可以通过JSON序列化,那就没关系了。闭包,函数,DOM节点等将不工作!