关于使用JavaScript脚本记录用户鼠标点击行为

分析用户在网站上的行为主要有两种方式,一种较为宏观,主要是通过分析后台日志,分析用户在各个页面之间的跳转关系,另一种较为微观,主要是通过在页面上的 JavaScript 脚本记录下用户的鼠标、键盘等行为,分析用户在单个页面上的操作。本文主要是对后一种方法中的使用脚本记录用户鼠标行为的一些尝试的总结。

用户在网页上的行为是很复杂的,有很多行为(比如视线的移动)如果没有专门的设备很难取到,大多数情况下,我们能直接取到的最有价值的信息是用户鼠标的行为(当然,还有一些用户从来不用鼠标,比如盲人用户),而鼠标行为中,处理起来最为简单的是鼠标的点击。下文中,如果没有特别说明,“点击”一词指的就是鼠标点击。

我们假设,用户在一次访问会话中,点击并不是随机的,除了部分无意的点击外,大部分点击都是有意义的,表示用户对当前的区域有兴趣(哪怕是误解)。基于这个假设,记录下用户的点击行为并进行分析是有意义的,通过分析用户的点击记录,可以找出页面上吸引用户的区域,这些区域不妨称之为热区。

接下来的问题就是,对于用户的点击,我们要记录些什么以及如何记录。

一、取得点击信息

对于网页来说,用户点击的位置信息似乎是最重要的信息。当然,除此之外,还有一些其它的信息也很重要,比如点击时间、用户会话 ID、用户浏览器信息等。

使用 JavaScript,我们可以很方便地取得用户在页面上的点击事件的位置坐标。然而,在现在流行的各大主流浏览器中,这个坐标通常是相对于浏览器网页可见区域的左上角的坐标,有时页面上有滚动条,并且已经拖动了一段距离,就要再取得页面被卷去的部分的高度或宽度,以便得到点击事件距页面左上角的坐标。

这一步并不是那么简单,比如同一个网页在不同的浏览器中可能有不同的表现。当然,这个问题对于有专业前端开发人员的网站来说很容易解决(或者故意不解决)。更麻烦的是,用户的显示器分辨率不同,网页内容部分在页面中的位置也可能不同。

比如,网页内容一般有固定宽度或自适应宽度两种不同的布局方式。像淘宝首页(http://www.taobao.com/)就是固定宽度,无论你在什么分辨率的显示器下看,页面的宽度不会变化,只是页面两侧的空白不同;而亚马逊首页(http://www.amazon.com/)则是自适应宽度,在不同分辨率下,页面内容宽度会自动缩放以填满屏幕。

对于像亚马逊这样内容自适应宽度的网页,我暂时没有想到简单的处理办法,下面我们只讨论像淘宝首页这样内容固定宽度的页面。

内容固定宽度的页面根据内容在页面的位置主要有三种布局:居左、居中、居右。如下图所示。

内容固定宽度的页面的三种布局

三种布局记录点击位置信息的方法各不一样,原则是,记录下的位置信息应该是相对于网页内容的,与用户使用的显示器的分辨率无关。即如果用户 A 与用户 B 都点击了页面上同一个小图标,无论他们的显示器分辨率是否相同,记录下来的点击位置都应该是相同或相近的。

对于固定宽度居左的页面处理起来最为简单,因为我们能很容易取得当前点击相对于页面左上角(注意是整个页面的左上角,而不是页面可见区域的左上角)的坐标,无论用户屏幕的分辨如何,理想情况下这个坐标都是一致的,因此,直接记录点击事件相对于页面左上角的坐标就可以了。

类似地,固定宽度居右的页面处理起来也很简单,记录点击事件相对于页面右上角的坐标就可以了。不过这类布局在国内似乎很少见。

固定宽度居中的页面特殊一些,在不同浏览器下左右两侧的空白宽度不一样,因此取左上角或右上角都不合适。但只要想到,我们的坐标值其实可以是负数,就很容易解决了,可以取页面顶部中点为原点,记录点击位置相对于这个点的坐标就行了。

内容固定宽度的页面的三种布局及对应的原点坐标

除了点击位置信息,我们经常还对另外一个信息有兴趣:当前点击是不是点在一个超链接上?一般来说,点在超链接上意味着用户将被带到另一个页面(或当前页面的另外一个部分),这对于网站方来说,是乐于看到的。而点在非超链接上意味着一次无效的点击(当然,一些网页游戏或类似应用例外),这可能是一次无意中的点击,也可能是用户以为这个地方可以点击,于是在上面点了一下,但发现什么也没有发生,这种情况通常意味着设计可能有问题。

当前点击是否点在超链接上这个信息是很有价值的。我们暂且称那些点到超链接上的点击为“有效点击”,对应地,点到非超链接上的点击为“无效点击”。这儿的有效、无效主要是指当前点击对于页面转化是否有效,并不是真正的说点到非链接区域的点击是无效或没用的,事实上,无效点击可能比有效点击更值得关注,而且更重要的是,无效点击由于没有发生页面跳转(转化),不会在服务器上留下日志记录,因此,这类点击信息只有通过网页脚本的方式来记录。

顺便提一下,如果需要记下有效点击的 a 元素的 href 属性值,需要考虑 IE6 下 URL 中包含汉字的问题,具体可见我之前写的IE6下使用JS获取路径中包含汉字的URL的一个问题

除了以上信息外,你可能还需要记录一些额外的信息,具体的可根据实际需求及资源而定,这儿暂不讨论。

二、发送信息

记下了点击信息,如何发送出去呢?

考察了若干类似的系统,目前比较流行的方式似乎是将要发送的信息加到 URL 参数中,请求打点服务器上的一个非常小的空图片,这样,信息就将记录在打点服务器的日志(比如 apache 日志)中,之后再用专门的程序从日志中读取并分析相关信息。而且,对于打点服务器而言,由于只需要提供一个非常小的静态图片的访问,所以一台普通的服务器经过适当配置后也可以应对很高的访问量。

在 JavaScript 中,构造一个图片请求非常容易,比如:

var img = new Image();
img.src = "http://xxx.xxx/img.gif?a=1&b=2....";

但这儿也有一些需要注意的地方。比如当点击在一个链接上时,页面很快就会发生跳转,而如果跳转之前 img 的请求还没有成功发出的话,这个请求就会丢失。当然,可以在发送 img 请求时设法先把页面跳转阻塞,img 请求发送完成后再继续跳转,但这种做法侵入性太高,有可能会危害用户体验,一般情况下不建议这么做。

一个减少这种情况发生的方案是,绑定 mousedown 事件而不是 click 事件,在鼠标按键按下之时即发送 img 请求。我们知道,只有在鼠标按键按下(mousedown)再弹起(mouseup)之后才是点击(click)事件(不考虑部分移动设备上的浏览器),而正常人在鼠标按下与弹起之间还有几十至一两百毫秒的时间差,有这额外的一点时间,虽然很少,但对于提高 img 请求发送的成功率来说已经很有帮助了。如果再优化一下打点服务器,让每次 img 请求响应都能尽可能快,因页面跳转发生的记录丢失就会降低很多(不过理论上还是会有一些)。

还有一个需要注意的是,在某些浏览器中,如果页面过于复杂,会频繁地触发浏览器的垃圾回收机制,如果刚好 img 又都是些没有引用的局部变量,有一些 img 就会被强制回收,请求也就发不出去了。关于这个问题,可以参考这个页面。比较好的做法是,先将 img 在某个全局变量中引用,等 img onload 或 onerror 时再将这个引用去掉。

有时也需要考虑,这一段监测用户鼠标点击行为的脚本应该放在页面的哪个位置。当然,放得越靠前越好,因为如果放得太靠后,并且网页加载速度不是很快的话,有可能监测脚本还没有加载用户就已经开始点击了,而这些点击记录显然也会丢失。但不少页面需要尽快向用户呈现首屏内容,对于这些页面来说,监测需求相对不是第一位的,监测脚本可以放到后面一些的位置。

另外,监测代码如果想写得尽量通用一些,不指定网页内容的根元素是哪一个的话(或者指定了根元素,但监测代码放在了根元素之前如 head 中),mousedown 事件基本上就要绑定到 document 对象上,这时,需要注意点击到网页滚动条上的记录是否要忽略的问题。

如何判断一个点击是否点在了页面的滚动条上是个有趣的问题,一个简单的办法是判断当前事件元素的父元素,如果这个元素的 tagName 直接就是“HTML”了,那说明当前点击到了滚动条上,不然的话,父元素应该是一个“DIV”、“BODY”之类的元素。

对于前端来说,需要做的大致就是上面这些工作了。当然,记录数据只是第一步,接下来还有漫长的数据分析过程,不过那是另外的一系列问题,以后的帖子中再继续探讨。

9 Replies to “关于使用JavaScript脚本记录用户鼠标点击行为”

    1. 丢失率和要跳转到的页面的响应速度以及打点服务器的响应速度有很大关系,所以可能没有一个一般的数字。我们在内部环境中测试过,在我们的环境下丢失率很小,是可以接受的,但真实的线上环境中的丢失率的数字我也还没有,这个数字恐怕很难精确统计,因为数据丢失时几乎不会留下任何可以监测的痕迹。不知道你有没有好的想法。

  1. 发送点击数据有其他方法,但是必需要分类:链接类,可以把坐标数据夹带在目标链接里(post方式还是url参数自行考虑),例:/123.html?123_456(想用户看不到的可以用post方式,后台处理完还可以再转向到/123.html,消除用户刷新的时候浏览器提示是否再次提交post信息)好处在于减少了一个request,功能类,例如焦点图的1,2,3,4切换,这种就用你的那个img.src就挺好

    1. 把数据夹带在目标链接里的想法不错,第一次看到,多谢分享!:-)
      不过这种做法似乎也有一个问题,就是打点模块与网站自身的功能会结合得比较紧,需要修改网站页面的业务逻辑,对于一些大中型网站或者较老的网页来说,可能成本会高一些…

  2. 博主,你好。我是一个大二的学生(开学大三),做了一年的Asp.Net。我以后想从事前端工程师一类的工作,在这个暑假的时候自学了javascript,css+div。总之自我感觉好像入了门,现在想从博主这儿取点经。(1)关于javascript,你觉得我应该怎样做,才能有比价大的提高喃?(2)项目经验的问题,我现在的项目经验都是Asp.Net的,我觉得如果以后要想找前端工程师这一类的实习工作有点悬,我应该怎样做喃?谢谢博主抽空回答一下。

    1. 非常抱歉,今天偶然才重新看到这条留言,不知道现在回复会不会太晚。
      我觉得最重要的是多练习,自己给自己找些项目来做,编程语言只有多实践才能有充分的理解。当然,每隔一段时间要抬起头回顾一下,然后再看一些业界大家推荐的书籍。

  3. hi, 博主好,最近正好在做一个类似的功能,想请教一下如果获取固定宽度居中及居右情况下的坐标。就是相对于视窗中点或视窗右上角的坐标?
    期待回复~

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s