PhantomJS; 点击一个元素

83

我该如何在PhantomJS中点击一个元素?

page.evaluate(function() {
    document.getElementById('idButtonSpan').click();  
});

这给我一个错误:"undefined不是一个函数..."

如果我改成

 return document.getElementById('idButtonSpan');

然后打印它,

接着它会打印出 [object object],因此这个元素是存在的。

这个元素看起来像一个按钮,但实际上只是一个 span 元素,而不是一个提交输入。

我能够使用 Casper 让这个按钮点击工作,但 Casper 有其他限制,所以我又回到了 PhantomJS。


29
接受一个答案的时间。 - user663031
有3个答案使用“dispatchEvent”函数,2个使用“sendEvent”,一个几乎没有用,一个应该是注释。 - redbeam_
不要忘记加上 # 号... - GracefulCode
为什么还没有人指出click()在DOM API中根本不存在,你可能是在jQuery或类似的库中看到它的? - YemSalat
4年后:答案被接受了!我已经不再使用PhantomJS,所以无法验证答案。但是我会接受58个赞同的结论 :) @torazaburo - user984003
11个回答

68

.click() 不是标准的。你需要创建一个事件并分派它:

function click(el){
    var ev = document.createEvent("MouseEvent");
    ev.initMouseEvent(
        "click",
        true /* bubble */, true /* cancelable */,
        window, null,
        0, 0, 0, 0, /* coordinates */
        false, false, false, false, /* modifier keys */
        0 /*left*/, null
    );
    el.dispatchEvent(ev);
}

9
用jQuery包装el后,你就可以得到这个click的定义。它适用于你的浏览器以及Phantom。$(el).click() - Bluu
3
哇塞,感动得快哭了!经过将近12个小时的不间断努力终于搞定了!嗯嗯(鼻子发酸的声音)。 - user1323136
1
对我来说也很好用,但是必须记住在处理完成之前不要过早退出PhantomJS。我需要一个简短的脚本只点击一个按钮并退出。在page.onLoadFinished = function() {...};中调用phantom.exit()之前,这对我来说是无法工作的。 - gregko
document.querySelector(element).click() 对我来说完全正常工作。 - GracefulCode
为了使用自定义控件,我不得不使用更复杂的解决方案,其中包括3个事件:function triggerMouseEvent(elm, eventType) { var ev = document.createEvent("MouseEvent"); ev.initMouseEvent( eventType, true /* 冒泡 /, true / 可取消 /, window, null, 0, 0, 0, 0, / 坐标 / false, false, false, false, / 修改键 */ 0 /左键/, null ); elm.dispatchEvent(ev); }function click(elm) { triggerMouseEvent(elm, 'mousedown'); triggerMouseEvent(elm, 'mouseup'); triggerMouseEvent(elm, 'click'); } - a-bobkov
这对我不起作用。有人能看一下http://stackoverflow.com/questions/41560375/why-does-the-button-click-not-happen-phantomjs并指出我是否错过了什么吗? - Red Cricket

34

除了@torazaburo的回答之外,当在PhantomJS中运行时,您可以对HTMLElement.prototype.click进行存根。例如,我们使用PhantomJS + QUnit运行我们的测试,在我们的qunit-config.js中有这样的内容:

if (window._phantom) {
  // Patch since PhantomJS does not implement click() on HTMLElement. In some 
  // cases we need to execute the native click on an element. However, jQuery's 
  // $.fn.click() does not dispatch to the native function on <a> elements, so we
  // can't use it in our implementations: $el[0].click() to correctly dispatch.
  if (!HTMLElement.prototype.click) {
    HTMLElement.prototype.click = function() {
      var ev = document.createEvent('MouseEvent');
      ev.initMouseEvent(
          'click',
          /*bubble*/true, /*cancelable*/true,
          window, null,
          0, 0, 0, 0, /*coordinates*/
          false, false, false, false, /*modifier keys*/
          0/*button=left*/, null
      );
      this.dispatchEvent(ev);
    };
  }
}

1
提醒一下,我正在使用Karma 0.12.17和PhantomJs 1.9.7-14。没有window._phantom对象,所以我只是删除了那个条件,它按预期工作。 - BradGreens
我在想这个函数是否应该接受参数,以便为MouseEvent设置不同的坐标。 - ffflabs

16

这不是很美观,但我一直在使用它来允许我使用jQuery进行选择:

var rect = page.evaluate(function() {
    return $('a.whatever')[0].getBoundingClientRect();
});
page.sendEvent('click', rect.left + rect.width / 2, rect.top + rect.height / 2);

如果不使用jQuery,但你仍然可以用document.querySelector(s)替换$(s)[0]

需要注意的是这依赖于元素在视图中,也就是说你的viewportSize.height必须足够大。


2
尝试了所有可能的方法,当我尝试点击“tr”时,这是唯一有效的选项。 - Kai
在phantomjs 1.9.0上工作,并使用<a>元素。 - redbeam_
1
在我看来,最好的解决方案是+1 - Flash Thunder

8

希望以下方法有用。在1.9版本中,它对我有效。

page.evaluate(function(){
    var a = document.getElementById("spr-sign-in-btn-standard");
    var e = document.createEvent('MouseEvents');
    e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    a.dispatchEvent(e);
    waitforload = true;
});

这对我有用。希望对其他人也有帮助。

@Jobins John,waitforload = true 是什么意思? - Qadir Hussain
1
@QadirHussain 实际上是在等待页面完全加载。这就像设置一个特定的时间来加载页面。 - Jobins John

6

您可以使用evaluate函数来编写简单的JavaScript代码,例如:

page.evaluate(function() {
    document.getElementById('yourId').click();
});

1
实际上,现在使用PhantomJS 2.x已经是正确的解决方案了。 - BlaM

6

使用 1.9.2 版本,这对我有效,单击处理程序被触发:

var a = page.evaluate(function() {
    return document.querySelector('a.open');
});

page.sendEvent('click', a.offsetLeft, a.offsetTop);

它不在所有元素上都有。例如,<a> 没有它。在按钮上它是存在的。 - unludo

3

我从来无法直接点击该元素。相反,我查看了HTML以查找使用onclick调用的函数,然后调用了那个函数。


如果函数是通过addEventListener添加的,你该如何找到它并调用它呢? - Suo6613

2

使用Phantomjs 2.0时,Document.querySelector(element).click()可以起作用。

click: function (selector, options, callback) {
    var self = this;
    var deferred = Q.defer();
    options = options || {timeout:1000}; 
    setTimeout(function () { 
        self.page.evaluate(function(targetSelector) {
            $(document).ready(function() {
                document.querySelector(targetSelector).click();
            }) ;
        }, function () {
                deferred.resolve();
        }, selector);
    }, options.timeout);
    return deferred.promise.nodeify(callback);
},

2
最简单的方法是使用jQuery。
page.evaluate(function() {
  page.includeJs("your_jquery_file.js", function() {
    page.evaluate(function() {
      $('button[data-control-name="see_more"]').click();
    });
  });
});

2

PhantomJS也可以实现双击。

推荐

这是从答案stovroz改编而来,触发本地dblclick事件,包括mousedownmouseupclick事件(每个事件都有两个)。

var rect = page.evaluate(function(selector){
    return document.querySelector(selector).getBoundingClientRect();
}, selector);
page.sendEvent('doubleclick', rect.left + rect.width / 2, rect.top + rect.height / 2);

其他方法

以下两种方法仅触发dblclick事件,但不会触发应该在其之前触发的其他事件。

改编自此答案,作者为torazaburo

page.evaluate(function(selector){
    var el = document.querySelector(sel);
    var ev = document.createEvent("MouseEvent");
    ev.initMouseEvent(
        'dblclick',
        true /* bubble */, true /* cancelable */,
        window, null,
        0, 0, 0, 0, /* coordinates */
        false, false, false, false, /* modifier keys */
        0 /*left*/, null
    );
    el.dispatchEvent(ev);
}, selector);

摘自Jobins John此答案

page.evaluate(function(selector){
    var el = document.querySelector(sel);
    var e = document.createEvent('MouseEvents');
    e.initMouseEvent('dblclick', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    el.dispatchEvent(e);
}, selector);

完整的测试脚本


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接