【问题标题】:How do I access an iframe from CasperJS?如何从 CasperJS 访问 iframe?
【发布时间】:2012-08-27 21:56:53
【问题描述】:

我有一个带有 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

有什么办法可以做到这一点吗?涉及直接戳入 phantomjs 的 hack 会很好,但我不知道在那里做什么。

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

【问题讨论】:

    标签: javascript iframe webkit phantomjs casperjs


    【解决方案1】:

    一直在寻找这个,当然我在发布问题后几分钟就找到了答案。

    我可以使用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();
    });
    

    【讨论】:

    • 吉姆,你有没有碰巧知道切换后你能不能 this.test.assertVisible('#someElemInsideIframe') ?似乎对我来说很糟糕,但 this.click(...) 有效。
    • 我没有,抱歉。可见性可能会以其他一些不适用于框架的方式进行测试,我不确定。
    • 你看到@olleolleolle 的回答了吗? withFrame 是一个文档化的方法。
    • 是的,我做到了。当我提出这个问题或接受这个答案时,withFrame 并不存在,但听起来从现在开始使用它是正确的。
    【解决方案2】:

    从 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 或 1),因为像 twitter(通过 addthis)这样的社交服务经常在后台加载自己的 iframe。
    • 你可以使用框架索引而不是框架名称 - docs.casperjs.org/en/latest/modules/casper.html#withframe
    【解决方案3】:

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

    【讨论】:

    • 不相关——这个例子是同域 iframe,跨域安全不是我的问题。请参阅我自己的答案(那里仍然不需要--web-security=no)。
    【解决方案4】:

    假设我们有不同的帧(frame1 和 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");
                }
          );
       });
    });
    

    【讨论】:

      【解决方案5】:

      你可以这样做:

      casper.start("url here...", function() { 
          this.withFrame(0, function() {
              this.evaluate(function() {
                  document.querySelector('img#btn_start').click();
              })
          })
      });
      

      您可以将零替换为 iframe 的名称。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-30
        • 1970-01-01
        • 2017-10-22
        • 1970-01-01
        • 1970-01-01
        • 2016-03-21
        • 1970-01-01
        相关资源
        最近更新 更多