PhantomJS; 点击一个元素


81

如何单击PhantomJS中的元素?

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

这给我一个错误“未定义不是函数...”

如果我代替

 return document.getElementById('idButtonSpan');

然后打印

然后打印[object object],因此该元素确实存在。

该元素充当按钮,但实际上只是一个span元素,而不是Submit输入。

我可以单击此按钮来与Casper一起使用,但是Casper还有其他限制,所以我回到PhantomJS。


28
是时候接受答案了。

使用“ dispatchEvent”功能的答案有3种,使用“ sendEvent”功能的答案有2种,其中一种实际上几乎没有用,而另一种则应为注释。
redbeam_ 2015年

不要忘了#号...
GracefulCode

为什么还没有人指出click()DOM API中根本不存在,您可能在jQuery或类似的lib中看到了它?
YemSalat

4年后:接受答案!我远离PhantomJS,所以无法验证答案。但我会接受58个正确的投票:) @torazaburo
user984003

Answers:


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
el用jQuery包装可以为您提供这种点击定义。它可以在您的浏览器和Phantom中使用。$(el).click()
2013年

3
经过了将近12个小时的不断奋斗,omg喜悦的眼泪!嗅探嗅探!
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 /可取消/,窗口,null, 0,0,0,0 ,/坐标/ false,false,false,false,/修饰键* / 0 / *左* /, 空值 ); elm.dispatchEvent(ev); }函数click(elm){triggerMouseEvent(elm,'mousedown'); triggerMouseEvent(elm,'mouseup'); triggerMouseEvent(elm,'click'); }
a-bobkov

34

除了@torazaburo的响应,您可以HTMLElement.prototype.click在PhantomJS中运行时进行存根。例如,我们使用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
提示我正在使用PhantomJs 1.9.7-14运行Karma 0.12.17。没有任何window._phantom对象,所以我删除了该条件,它按预期工作。
BradGreens 2014年

我想知道函数是否应该接受参数以便为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,您可以随时替换$(s)[0]document.querySelector(s)

(它确实依赖于考虑中的元素,即您的viewportSize.height足够大)。


2
尝试了所有可能的方法,这是尝试单击时唯一对我有用的选项tr
2015年

使用phantomjs 1.9.0并使用<a>元素
redbeam_ 2015年

1
最佳解决方案imo+1
Flash Thunder

10

希望以下方法会有用。在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?
卡迪尔·侯赛因

1
@QadirHussain它实际上在等待页面完全加载。几乎就像设置特定时间来加载页面一样。
Jobins John

6

有了1.9.2这项功能,我便触发了点击处理程序:

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

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

并非所有元素。例如,<a>没有它。在按钮上就可以了。
2014年

6

使用带有的简单JavaScript evaluate,如下所示:

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

1
实际上,现在PhantomJS 2.x现在是正确的解决方案
BlaM

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

使用PhantomJS也可以双击。

推荐的

这是根据stovroz的答案改编而成,并触发了一个包含,和事件的事件(每个事件两个)。dblclickmousedownmouseupclick

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约翰

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);

完整的测试脚本


2

最简单的方法是使用jQuery。

page.evaluate(function() {
  page.includeJs("your_jquery_file.js", function() {
    page.evaluate(function() {
      $('button[data-control-name="see_more"]').click();
    });
  });
});

0

对于使用JQuery的用户,JQuery UI创建了一个实用程序来模拟这些:jquery-simulate。我在PhantomJS和Chrome中使用它

$ele..simulate( "click" );
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.