CasperJS中document.querySelectorAll无返回结果的问题排查与解决
CasperJS evaluate() 无法获取DOM元素的问题解决
你碰到的这个问题其实是CasperJS里一个很容易踩的坑——上下文隔离。我来给你拆解清楚:
问题根源
casper.evaluate()方法的作用是把代码注入到目标页面的浏览器上下文里执行,这个上下文和你写的Casper脚本本身的上下文是完全隔离的!
- 你最初的代码里,全局的
texts数组是定义在Casper脚本上下文里的,但grabParagraphs函数是在页面的浏览器上下文里跑的,它根本看不到这个texts变量,自然没法往里面push内容,所以最后输出的长度是0。 - 而
grabTitle能正常工作,是因为它直接返回了document.title的值,Casper会自动把这个值从页面上下文传递回你的脚本上下文,不需要共享变量。
正确的解决方案
解决思路很简单:在evaluate执行的函数内部处理数据,然后把结果返回给Casper脚本上下文,再在脚本里接收这个结果。就像你后来按照@Mario Nikolaus的建议修改的那样:
修正后的关键代码:
function grabParagraphs(){ var pars = document.getElementsByTagName("p"); var texts = []; for (var i=0; i<pars.length; i++){ texts.push(pars[i].textContent); } return texts; // 把结果返回给Casper脚本 } casper.then(function(){ var title = this.evaluate(grabTitle); this.echo("The title is: "+title); var texts = this.evaluate(grabParagraphs); // 接收返回的结果 this.echo(texts.length+" paragraphs found:\n"+texts) });
额外的小提示
- 优先用Casper自带的DOM方法:如果只是简单的获取元素、点击、输入,Casper提供了
casper.getElementsInfo()、casper.click()、casper.sendKeys()这类方法,不需要进入页面上下文,用起来更省心。比如获取所有p标签的文本可以写成:var texts = this.getElementsInfo('p').map(function(el) { return el.text; }); - 可靠等待元素加载:如果页面是动态加载的,
casper.waitForSelector('p')比固定的casper.wait(10000)更可靠,它会等到元素出现后再执行后续代码,避免因为加载慢导致的元素找不到问题。
内容的提问来源于stack exchange,提问作者Russell Teapot
相关产品推荐
相关产品推荐

