如何通过Java代码捕获浏览器上的用户操作?

时间:2012-03-21 13:23:06

标签: java selenium-webdriver htmlunit

我试图从我的Java代码中捕获应用程序的浏览器DOM。 目标是在Web浏览器上呈现Web应用程序。用户将填充字段或执行任何操作以在应用程序中导航。 将有一个独立的Java代码,它将捕获Web应用程序将导航到的每个页面的浏览器DOM。 我使用HtmlUnit捕获DOM和Selenium WebDriver来呈现Web应用程序,因为HtmlUnit是无头的。

问题是我无法跟踪我是否在应用程序的新页面上。 声明HtmlPage page = webClient.getCurrentWindow()。getEnclosedPage()不起作用,因为HtmlPage对象不会改变。

我尝试过实现DomChangeListener,但似乎没有DomChangeEvent,如果数据填充是手动完成的,即在java代码之外。如果我填充内容并从代码中提交页面,那么DomChangeListener可以正常工作。但那不是我想要的。

任何建议,如何实现这一目标?还有其他api对此有用吗?

此致

2 个答案:

答案 0 :(得分:1)

使用Selenium / Webdriver这不是一件容易的事。我做了一些非常相似的事情并让它发挥作用(我很快就会发布)。基础知识是JavaScript事件处理程序,并从Java轮询数据。

JavaScript:

var events = [];
var eventQueue = [];
var eventHistory = {};
var processing = false;

var nativeEvents = {
    'submit': 'HTMLEvents',
    'keypress': 'KeyEvents',
    'click': 'MouseEvents',
    'dblclick': 'MouseEvents',
    'dragstart': 'MouseEvents',
    'dragend': 'MouseEvents',
}

for(var eventName in nativeEvents) {
    document.addEventListener(eventName, processEvent, true);
};

processEvent = function(event) {
    if(event.triggeredManually) {
        return true;
    }
    if(event.type in nativeEvents) {
        storeEvent(event);
        event.stopPropagation();
        event.preventDefault();
        return false;
    }
}
storeEvent = function(event) {
    ev = convertEvent(event);
    if(processing) {
        eventQueue.push(ev);
    } else {
        events.push(ev);
    }
}

convertEvent = function(event) {
    var ev = {};
    var id = new Date().getTime() + ":" + Math.random();
    ev['id'] = id;
    ev['type'] = event.type;
    ev['target'] = event.target;
    ev['button'] = event.button;
    ev['charCode'] = event.charCode;
    ev['keyCode'] = event.keyCode;
    ev['altKey'] = event.altKey;
    ev['ctrlKey'] = event.ctrlKey;
    ev['shiftKey'] = event.shiftKey;
    ev['clientX'] = event.clientX;
    ev['clientY'] = event.clientY;
    ev['offsetX'] = event.offsetX;
    ev['offsetY'] = event.offsetY;
    eventHistory[id] = ev;
    return ev;
}

这些功能用于检测和存储用户事件。需要以下内容来检索Java中的事件并在事后对事件进行三舍五入。这是页面卸载所必需的,因为unload事件不能安全地在每个浏览器中运行。

getEvents = function() {
    processing = true;
    events = events.concat(eventQueue);
    eventQueue = [];
    setTimeout(resetEvents, 10);
    return events;
};

resetEvents = function() {
    events = [];
    processing = false;
};

triggerEvents = function(idsAsJson) {
    // trigger pending events
    var ids = JSON.parse(idsAsJson);
    for (var i = 0; i < ids.length; i++) {
        var event = eventHistory[ids[i]];
        if(event) {
            var evObj = null;
            var evObjType = null;
            var bubbling = true;
            var cancelable = false;

            if(event['type'] in nativeEvents) {
                evObjType = nativeEvents[event['type']];
                evObj = document.createEvent(evObjType);

                // more info: http://www.howtocreate.co.uk/tutorials/javascript/domevents
                if(evObjType == 'KeyEvents') {
                    evObj.initKeyEvent(event['type'], bubbling, cancelable, window, event['ctrlKey'], event['altKey'], event['shiftKey'], false, event['keyCode'], event['charCode']);
                } else if(evObjType == 'MouseEvents') {
                    evObj.initMouseEvent(event['type'], bubbling, cancelable, window, 1, event['offsetX'], event['offsetY'], event['clientX'], event['clientY'], event['ctrlKey'], event['altKey'], event['shiftKey'], false, event['button'], null);
                } else {
                    evObj.initEvent(event['type'], bubbling, cancelable);
                }
                evObj.triggeredManually = true;
                event['target'].dispatchEvent(evObj);
            }
        }
    }

};

然后你需要循环遍历getEvents()函数的Java代码,你可以存储你需要的任何东西。之后,您需要执行triggerEvents()函数以处理用户交互。

答案 1 :(得分:0)

不幸的是,我不熟悉HtmlUnit或Selenium WebDriver,所以这个答案可能对你没用。但是,一般来说,这种事情相对容易实现。

在浏览器端,只要有需要捕获的用户输入,就可以实现事件处理程序。这些事件处理程序将使用您需要在服务器上捕获的任何数据对您的Web服务器进行Ajax调用。如果数据完全复杂,我建议您使用Json将数据作为对象传递。有一些标准的Javascript字符串(参见https://github.com/douglascrockford/JSON-js)在Java方面,有一些工具可以将json字符串转换为java对象(参见http://code.google.com/p/google-gson/)。你也可以到这里寻找更多选择:http://www.json.org/

在服务器端,您的java代码只是驻留在jsps或servlet中。它处理数据。如果数据是瞬态的,您可以使用会话(javax.servlet.http.HttpSession)将其保留在内存中。如果它是持久的,您可以将其写入数据库或数据文件。

一般来说,我经常发现自己实现这种方式很有用,而不是使用软件包。我的解决方案通常更小,更容易调试和维护。希望这会有所帮助。