2012-08-27 61 views
31

我有一个带有iframe的网页。我想使用CasperJS访问iframe的内容。特别是,我需要点击按钮并填写表格。我怎样才能做到这一点?如何从CasperJS访问iframe?

主要网页是 main.html

<html><body> 
<a id='main-a' href="javascript:console.log('pressed main-a');">main-a</a> 
<iframe src="iframe.html"></iframe> 
<a id='main-b' href="javascript:console.log('pressed main-b');">main-b</a> 
</body></html> 

的iframe是:

<html><body> 
<a id='iframe-c' href="javascript:console.log('pressed iframe-c');">iframe-c</a> 
</body></html> 

我天真的做法:

var casper = require('casper').create({ 
    verbose: true, 
    logLevel: "debug" 
}); 

casper.start("http://jim.sh/~jim/tmp/casper/main.html", function() { 
    this.click('a#main-a'); 
    this.click('a#main-b'); 
    this.click('a#iframe-c'); 
}); 

casper.run(function() { 
    this.exit(); 
}); 

不行的,当然,这是因为a#iframe-c选择器在主框架中无效:

[info] [phantom] Starting... 
[info] [phantom] Running suite: 2 steps 
[debug] [phantom] opening url: http://jim.sh/~jim/tmp/casper/main.html, HTTP GET 
[debug] [phantom] Navigation requested: url=http://jim.sh/~jim/tmp/casper/main.html, type=Other, lock=true, isMainFrame=true 
[debug] [phantom] url changed to "http://jim.sh/~jim/tmp/casper/main.html" 
[debug] [phantom] Navigation requested: url=http://jim.sh/~jim/tmp/casper/iframe.html, type=Other, lock=true, isMainFrame=false 
[debug] [phantom] Successfully injected Casper client-side utilities 
[info] [phantom] Step 2/2 http://jim.sh/~jim/tmp/casper/main.html (HTTP 200) 
[debug] [phantom] Mouse event 'click' on selector: a#main-a 
[info] [remote] pressed main-a 
[debug] [phantom] Mouse event 'click' on selector: a#main-b 
[info] [remote] pressed main-b 
[debug] [phantom] Mouse event 'click' on selector: a#iframe-c 
FAIL CasperError: Cannot dispatch click event on nonexistent selector: a#iframe-c 
# type: uncaughtError 
# error: "CasperError: Cannot dispatch click event on nonexistent selector: a#iframe-c" 
CasperError: Cannot dispatch click event on nonexistent selector: a#iframe-c  
    /tmp:901 in mouseEvent 
    /tmp:365 in click 
    /tmp/test.js:9 
    /tmp:1103 in runStep 
    /tmp:324 in checkStep 

有没有什么方法可以使这项工作?涉及直接窥探幻影的黑客攻击会很好,但我不知道该怎么做。

我使用CasperJS版本1.0.0-RC1和phantomjs版本1.6.0。

回答

40

花了很长时间寻找这个,当然我发现问题后的答案分钟。

我可以在this commit中使用添加到phantomjs中的新帧切换命令。具体而言,this.page.switchToChildFrame(0)this.page.switchToParentFrame()功能。看来无证,而且似乎也该方法已经changed即将推出的版本,但它的工作:

var casper = require('casper').create({ 
    verbose: true, 
    logLevel: "debug" 
}); 

casper.start("http://jim.sh/~jim/tmp/casper/main.html", function() { 
    this.click('a#main-a'); 
    this.click('a#main-b'); 
    this.page.switchToChildFrame(0); 
    this.click('a#iframe-c'); 
    this.page.switchToParentFrame(); 
}); 

casper.run(function() { 
    this.exit(); 
}); 
+0

吉姆,你碰巧知道你是否可以切换后this.test.assertVisible('#someElemInsideIframe')?似乎barf为我,但this.click(...)的作品。 –

+0

我不会,对不起。可见性可能会以某种其他方式进行测试,但对框架效果不佳,我不确定。 –

+1

您是否看到@ olleolleolle的回答? withFrame是一种记录方法。 –

4

由于事实上,你必须使用由Phantomjs 1.5提供的新--web-security=no 功能,以便能够访问这些 iFrames及其内容。

+1

没有真正相关的 - 这个例子是一个同域iframe和跨域安全不是我的问题。看看我自己的回答是否有用(在那里仍然不需要'--web-security = no')。 –

35

从1.0可以使用withFrame

casper.open("http://www.example.com/page.html", function() { 
    casper.withFrame('flashHolder', function() { 
     this.test.assertSelectorExists('#the-flash-thing', 'Should show Flash'); 
    }); 
    }); 
+0

这怎么可能与具有动态名称的框架一起工作?我不能依赖帧索引(例如0或1),而是因为像twitter这样的社交服务(通过addthis)经常在后台加载自己的iframe。 – DynamicDan

+0

您可以使用帧索引而不是帧名称 - http://docs.casperjs.org/en/latest/modules/casper.html#withframe –

3

假设我们有不同的帧(帧1和frame2),我们必须访问这些框架的不同元素(如点击或检查div标签是否退出)。

casper.withFrame('frame1', function() { 
    var file = '//*[@id="profile_file"]'; 
    casper.thenClick(x(file)); 
}); 

casper.withFrame('frame2', function() { 
    casper.then(function() { 
    casper.waitForSelector('#pageDIV', 
      function pass() { 
       console.log("pass"); 
      }, 
      function fail(){ 
       console.log("fail"); 
      } 
    ); 
    }); 
});