Запись и воспроизведение javascript - PullRequest
9 голосов
/ 11 ноября 2011

Я знаю, что можно записывать движения мыши, прокрутку и нажатия клавиш. Но как насчет изменений в документе? Как я могу записать изменения в документ?

Вот моя попытка. Должен быть лучший, более простой способ хранения всех событий?

Я благодарен за все советы, которые я могу получить!

<!DOCTYPE html>
<html>
<head>
<title>Record And replay javascript</title>
</head>
<body id="if_no_other_id_exist">

<div style="height:100px;background:#0F0" id="test1">click me</div>
<div style="height:100px;background:#9F9" class="test2">click me</div>
<div style="height:100px;background:#3F9" id="test3">click me</div>
<div style="height:100px;background:#F96" id="test4">click me</div>



<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>

$(document).ready(function() {
var the_time_document_is_redy = new Date().getTime();
var the_replay = '';


$('div').live("click", function (){
var the_length_of_visit = new Date().getTime() - the_time_document_is_redy;


// check if the element that is clicked has an id
if (this.id)
{

the_replay =
the_replay
+
"setTimeout(\"$('#"
+
this.id
+
"').trigger('click')\","
+
the_length_of_visit
+
");"
;


alert (
"The following javascript will be included in the file in the replay version:\n\n"
+ 
the_replay
) // end alert

} // end if



// if it does not have an id, check if the element that is clicked has an class
else if (this.className)
{

// find the closest id to better target the element (needed in my application)
var closest_div_with_id = $(this).closest('[id]').attr('id');

the_replay =
the_replay
+
"setTimeout(\"$('#"
+
closest_div_with_id
+
" ."
+
this.className
+
"').trigger('click')\","
+
the_length_of_visit
+
");"
;


alert (
"The following javascript will be included in the file in the replay version:\n\n"
+ 
the_replay
) // end alert

} // end if

});






// fall back if there are no other id's
$('body').attr('id','if_no_other_id_exist');


// example of how it will work in the replay version
setTimeout("$('#test1').trigger('click')",10000);

});
</script>
</body>
</html>

Ответы [ 6 ]

20 голосов
/ 07 февраля 2017

Меня заинтересовал этот вопрос, и я реализовал здесь подтверждение концепции

https://jsbin.com/nemake/edit?js,output

Использование демоверсии

  • Попробуйте нажать запись, щелкнув по кнопке,нажмите запись еще раз, а затем нажмите кнопку воспроизведения.
  • Play создает <iframe>, вводит исходный HTML-код и воспроизводит пользовательские события.
  • Чтобы изменить масштаб, измените переменную REPLAY_SCALE в исходном коде.
  • Чтобы изменить скорость воспроизведения, измените переменную SPEED в исходном коде.
  • NB Я только что протестировал jsbin на chrome 56.

Подробности реализации:

  • Поддерживает перемещение мыши, нажатие и ввод текста.Я пропустил другие (прокрутка, изменение размера окна, наведение, фокус и т. Д.), Но должно быть легко расширяемым.
  • Прослушиватели событий обходят любые event.stopPropagation(), используя захват при прослушивании событий в документе.
  • Отображение воспроизведения в другом разрешении осуществляется с помощью zoom CSS3.
  • Можно нарисовать прозрачный холст, чтобы нарисовать линии мыши.Я использую простой div, поэтому никаких линий трассировки.

Замечания:

  • Представляя, что мы собираем пользовательские события на реальном веб-сайте.Поскольку обслуживаемая страница может меняться с настоящего момента до воспроизведения, мы не можем полагаться на сервер клиента при воспроизведении записи в iframe.Вместо этого мы должны сделать снимок html, всех запросов ajax и запросов ресурсов, сделанных во время записи.В демо я только снимок HTML для простоты.Однако на практике все дополнительные запросы должны храниться на сервере в режиме реального времени, так как они загружаются на страницу клиента.Кроме того, во время воспроизведения важно, чтобы запросы воспроизводились с той же временной шкалой, которая была воспринята пользователем.Для имитации временной шкалы запроса также должны быть сохранены смещение и продолжительность каждого запроса.Загрузка всех запросов страниц по мере их загрузки на клиенте замедлит работу клиентской страницы.Один из способов оптимизации этой загрузки может состоять в том, чтобы хэшировать md5 содержимое запроса перед его загрузкой, если хеш md5 уже присутствует на сервере, данные запроса не нужно повторно загружать.Кроме того, сеанс одного пользователя может использовать данные запроса, загруженные другим пользователем, с использованием этого метода хеширования.

  • При загрузке всех событий потребуется тщательное рассмотрение.Поскольку будет сгенерировано много событий, это означает много данных.Возможно, может быть выполнено некоторое сжатие событий, например, потеря некоторых из менее важных событий перемещения мыши.Запрос загрузки не должен быть сделан для каждого события, чтобы минимизировать количество запросов.События должны буферизироваться до тех пор, пока не будет достигнут размер буфера или тайм-аут перед загрузкой каждого пакета событий.Следует использовать тайм-аут, так как пользователь может закрыть страницу в любой момент, потеряв при этом некоторые события.

  • Во время воспроизведения исходящие запросы POST должны быть смоделированы для предотвращения дублирования событий в других местах.

  • Во время воспроизведения пользовательский агент должен быть подделан, но это может быть ненадежным при отображении исходного изображения.

  • Пользовательский код записи может конфликтовать с кодом клиента.например, jquery.Чтобы избежать этого, потребуется пространство имен.

  • Могут быть некоторые крайние случаи, когда при наборе текста и нажатии может не воспроизводиться тот же результирующий HTML, что и в оригинале, например, случайные числа, время и дата.От наблюдателей мутаций может потребоваться наблюдать изменения HTML, хотя они поддерживаются не во всех браузерах.Скриншоты могут оказаться полезными здесь, но могут доказать OTT.

12 голосов
/ 11 ноября 2011

Воспроизведение действий пользователя только с помощью Javascript - это сложная проблема .

Прежде всего, вы не можете перемещать курсор мыши, вы также не можете эмулировать наведение / наведение мыши. Так что большая часть взаимодействия пользователя со страницей исчезает.

Во-вторых, когда-то записанные действия, большую часть времени они должны быть воспроизведены в другой среде, чем они были записаны в первую очередь. Я имею в виду, что вы можете воспроизводить действия на экране с меньшим разрешением, другим клиентским браузером, другим обслуживаемым контентом на основе воспроизведения файлов cookie браузера и т. Д.

Если вы потратите время на изучение доступных служб, позволяющих записывать действия посетителей веб-сайта (http://clicktale.com, http://userfly.com/ и многие другие), вы увидите, что ни один из них способны полностью воспроизводить пользовательские действия , особенно когда речь идет о наведениях мыши, ajax, сложных JS-виджетах.

Что касается вашего вопроса об обнаружении изменений, внесенных в DOM - как сказал Крис Бискарди в своем ответе, существуют события мутации , которые предназначены для этого. Однако имейте в виду, что они не реализованы в каждом браузере. А именно, IE не поддерживает их (они будут поддерживаться начиная с IE 9, согласно этой записи в блоге на MSDN http://blogs.msdn.com/b/ie/archive/2010/03/26/dom-level-3-events-support-in-ie9.aspx).

Использование этих событий может быть подходящим для вас, в зависимости от варианта использования.

Что касается ", то лучше более простой способ хранения всех событий ". Существуют другие способы (с синтаксическим подходом) прослушивания событий по вашему выбору, однако обработка (= хранение) их не может быть обработана простым способом, если вы не хотите сериализовать целые объекты событий, что не было бы хорошей идеей, если бы вы отправили информацию об этом событии на какой-либо сервер для их хранения. Вам следует учитывать тот факт, что при использовании веб-сайта происходит огромное количество событий, следовательно, существует огромный объем потенциальных данных, которые будут сохранены / отправлены на сервер.

Надеюсь, я прояснил ситуацию, и вы найдете эту информацию полезной. Я сам принимал участие в проекте, целью которого было добиться того, чего вы пытаетесь достичь, поэтому я знаю, насколько это может быть сложно, если вы начнете копаться в предмете.

3 голосов
/ 11 ноября 2011

Полагаю, вы ищете мутационные события.

http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-eventgroupings-mutationevents

Вот несколько ресурсов для вас:

http://tobiasz123.wordpress.com/2009/01/19/utilizing-mutation-events-for-automatic-and-persistent-event-attaching/

http://forum.jquery.com/topic/mutation-events-12-1-2010

https://github.com/jollytoad/jquery.mutation-events

Обновление:

В ответ на комментарий, очень, очень простая реализация:

//callback function
function onNodeInserted(){alert('inserted')}
//add listener to dom(in this case the body tag)
document.body.addEventListener ('DOMNodeInserted', onNodeInserted, false); 
//Add element to dom 
$('<div>test</div>').appendTo('body')

Как сказал WTK, вы попадаете на сложную территорию.

2 голосов
/ 26 апреля 2017

Запись

Сохраните исходный DOM страницы, удалите из него сценарии, а также вам нужно изменить все относительные URL-адреса на абсолютные.

Затем запишите мутации DOM и событие «Клавиатура / мышь».

Replay

Начните с начального сохраненного DOM, примените мутации и события, используя порядок меток времени.

Фактически, клики ничего не сделают, потому что мы удалили все сценарии. но поскольку мы сохранили изменения DOM, мы можем воспроизвести эффект после щелчка.

0 голосов
/ 09 мая 2019

Я нашел эти два решения на github, которые позволяют вам захватывать события и затем воспроизводить их на удаленном сервере.

https://github.com/ElliotNB/js-replay

и более комплексное решение

https://github.com/rrweb-io/rrweb

https://www.rrweb.io/#demos

У обоих есть демоверсии, которые вы можете попробовать.

0 голосов
/ 14 мая 2018

В последнее время мы можем использовать MutationObserver

MutationObserver предоставляет разработчикам способ реагировать на изменения в DOM.Он предназначен для замены событий мутации, определенных в спецификации событий DOM3.

Медленная демонстрация, поскольку сообщение console.log огромно.

var mutationObserver = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation)
  })
})
mutationObserver.observe(watchme, {
  attributes: true,
  characterData: true,
  childList: true,
  subtree: true,
  attributeOldValue: true,
  characterDataOldValue: true
})
<div id="watchme" contenteditable>
  Hello world!
</div>
...