PhantomJS; щелкните элемент


81

Как мне щелкнуть элемент в PhantomJS?

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

Это дает мне ошибку "undefined не является функцией ..."

Если я вместо этого

 return document.getElementById('idButtonSpan');

а затем распечатайте его,

затем он печатает [объект объект], значит элемент действительно существует.

Элемент действует как кнопка, но на самом деле это просто элемент диапазона, а не ввод для отправки.

Мне удалось нажать эту кнопку для работы с Casper, но у Casper были другие ограничения, поэтому я вернулся к PhantomJS.


28
Пора принять ответ.

Есть 3 ответа, которые используют функцию "dispatchEvent", 2, которые используют "sendEvent", один практически бесполезный и один, который должен быть комментарием.
redbeam_

Не забудьте знак # ...
GracefulCode

Почему никто еще не указал, что этого click()вообще нет в DOM API, вы, наверное, видели это в jQuery или какой-то подобной библиотеке?
YemSalat

4 года спустя: ответ принят! Я ушел из PhantomJS, поэтому не смог проверить ответ. Но я согласен, что 58 голосов за правильные :) @torazaburo
user984003

Ответы:


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()
Bluu 05

3
омг слезы радости, после почти 12 часов непрерывной борьбы с этим! нюх нюх!
user1323136

1
У меня тоже сработало, но нужно помнить, что не следует выходить из PhantomJS слишком рано, до завершения обработки. Мне нужен был короткий сценарий, чтобы просто нажать одну кнопку и выйти. Это не сработает для меня, пока я не вызову phantom.exit () из page.onLoadFinished = function () {...};
gregko

document.querySelector (element) .click () отлично работает для меня.
GracefulCode

Для работы с пользовательскими элементами управления мне пришлось сделать более сложное решение с тремя событиями: function triggerMouseEvent (elm, eventType) {var ev = document.createEvent ("MouseEvent"); ev.initMouseEvent (eventType, true / * bubble /, true / cancelable /, window, null, 0, 0, 0, 0, / координаты / false, false, false, false, / ключи-модификаторы * / 0 / * left * /, ноль ); elm.dispatchEvent (ev); } функция click (вяз) {triggerMouseEvent (вяз, 'mousedown'); triggerMouseEvent (вяз, 'mouseup'); triggerMouseEvent (вяз, 'щелчок'); }
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
Хедз-ап, что я использую 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);

но вы всегда можете заменить его $(s)[0]на, document.querySelector(s)если не используете jQuery.

(Он полагается на элемент, имеющийся в виду, т.е. ваш viewportSize.height достаточно велик).


2
Пробовал все возможные подходы, и это единственный вариант, который у меня сработал при попытке нажать tr.
Кай

Работал над phantomjs 1.9.0 и с элементом <a>
redbeam_

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, Джон, что waitforload = true?
Кадир Хуссейн

1
@QadirHussain На самом деле он ждет полной загрузки страницы. Это почти как установка определенного времени для загрузки страницы.
Джобинс Джон

6

У 1.9.2меня это сработало, сработали обработчики кликов:

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

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

Это не по всем элементам. Например, в <a> его нет. На кнопках он есть.
unludo

6

используйте простой JavaScript evaluate, например:

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

1
На самом деле теперь это правильное решение с PhantomJS 2.x
BlaM

3

Мне никогда не удавалось напрямую щелкнуть элемент. Вместо этого я просмотрел html, чтобы узнать, какая функция была вызвана с помощью onclick, а затем вызвал эту функцию.


как найти функцию и как ее вызвать, если она была прикреплена через addEventListener?
Suo6613

2

Document.querySelector (element) .click () работает при использовании Phantomjs 2.0

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 и запускает уроженец dblclickвключая mousedown, mouseupи clickсобытие (два из каждых).

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 создал служебную программу для имитации этого: jquery-simulate . Я использую это в PhantomJS и Chrome

$ele..simulate( "click" );
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.