网站统计的基本流程
首先,用户的行为会触发浏览器对被统计页面的一个http请求,这里姑且先认为行为就是打开网页。当网页被打开,页面中的埋点javascript片段会被执行,用过相关工具的朋友应该知道,一般网站统计工具都会要求用户在网页中加入一小段javascript代码,这个代码片段一般会动态创建一个script标签,并将src指向一个单独的js文件,此时这个单独的js文件会被浏览器请求到并执行,这个js往往就是真正的数据收集脚本。数据收集完成后,js会请求一个后端的数据收集脚本,这个脚本一般是一个伪装成图片的动态脚本程序,可能由phy、python或其它服务端语言编写,js会将收集到的数据通过http参数的方式传递给后端脚本,后端脚本解析参数并按固定格式记录到访问日志,同时可能会在http响应中给客户端种植一些用于追踪的cookie。
数据收集具体细节
- 通过浏览器内置javascript对象收集信息,如页面title(通过)、referrer(上一跳url,通过)【referrer 属性可返回载入当前文档的文档的 URL】、用户显示器分辨率(通过)、cookie信息(通过)等等一些信息。
- 创建一个最基本的发送统计的发送函数,用于创建img,发送统计请求到数据采集平台(后台)。详细代码见七埋点实例中的创建img
后端脚本执行阶段
- (1)解析http请求参数的信息。
- (2)从服务器(WebServer)中获取一些客户端(前端)无法获取的信息,如访客ip等。
- (3)将信息按格式写入log。
- (4)生成一副1×1的空gif图片作为响应内容并将响应头的Content-type设为image/gif。
- (5)在响应头中通过Set-cookie设置一些需要的cookie信息。
~~~~如果没有跨站跟踪同一用户的需求,可以通过js将cookie种植在被统计站点的域下,如果要全网统一定位,则通过后端脚本种植在服务端域下。
埋点代码
<script type="text/javascript">
var _maq = _maq || [];
_maq.push(['_setAccount', '网站标识']);
(function() {
var ma = ('script'); = 'text/javascript'; = true;
= ('https:' == ? 'https://analytics' : 'http://analytics') + './';
var s = ('script')[0]; (ma, s);
})();
</script>
前端统计脚本
(function () {
var params = {};
//Document对象数据 if(document) {
= || '';
= || '';
= || '';
= || '';
}
//Window对象数据 if(window && ) {
= || 0;
= || 0;
= || 0;
}
//navigator对象数据 if(navigator) {
= || '';
}
//解析_maq配置 if(_maq) {
for(var i in _maq) {
switch(_maq[i][0]) {
case '_setAccount':
= _maq[i][1];
break;
default:
break;
}
}
}
//拼接参数串 var args = '';
for(var i in params) {
if(args != '') {
args += '&';
}
args += i + '=' + encodeURIComponent(params[i]);
}
//通过Image对象请求后端脚本 var img = new Image(1, 1);
= '后端脚本地址?' + args;
})();
名词解释
流量的意思包含了很多:页面浏览数(PV)、独立访问者数量(UV)、IP、页面停留时间、页面操作时间、页面访问次数、按钮点击次数、文件下载次数等。
埋点实例脚本
- 借助新浪IP地址库,显示本地城市名称:
<script src="/iplookup/?format=js" type="text/ecmascript"></script>
remote_ip_info.country
remote_ip_info.province
remote_ip_info.city
- 获取客户端IP:
<script type="text/javascript" src="http:///?js=1"></script>
- 获取用户的访问开始时间、访问结束时间、以及用户与网站的交互时间(当用户在网页无操作时间超过30秒,理解为离开网页),其中无操作包括:鼠标点击、移动、滑轮无操作,键盘无按键操作。
var start = new Date();
var strStart = ()+"-"+(()+1)+"-"+()+" "+
()+":"+()+":"+();
var len = 0;
var end;
var status = "in";
var second = 30;
function revive(){
if(status == "out"){
start = new Date();
status = "in";
}
second = 30;
}
(function(){
second -= 1;
if(0 == second){
end = new Date();
len += (() - ())/1000;
status = "out";
}
},1000);
$(‘body‘).click(function(){
revive();
});
$(‘body‘).mousedown(function(){
revive();
});
$(‘body‘).mouseup(function(){
revive();
});
$(‘body‘).mousemove(function(){
revive();
});
//(Firefox)
$(‘body‘).bind(‘DOMMouseScroll‘, function() {
revive();
});
//(IE,Google)
$(‘body‘).bind(‘mousewheel‘,function(){
revive();
});
$(‘body‘).keydown(function(e){
revive();
});
$(‘body‘).keyup(function(e){
revive();
});
$(‘body‘).keypress(function(e){
revive();
});
= function(){
end = new Date();
var strEnd = ()+"-"+(()+1)+"-"+()+" "+
()+":"+()+":"+();
len += (() - ())/1000;
var img = new Image();
= contextPath + "behavior?stayTime=" + len + "&strStart" + strStart + "&lastDate=" + strEnd;
};
- 获取点击按钮
<a onclick="return getid()"> 按钮</a>
function getid(id) {
var img = new Image();
= contextPath + "button?prettyprint"> function sendUrl(url) {
let img = new Image(); // 创建一个img对象
let key = 'project_log_' // 为本次数据请求创建一个唯一id
+ Math.floor(Math.random() * 2147483648).toString(36);
window[key] = img; // 用一个数组维护img对象
= = = function () {
= = = null; // 清除img元素
window[key] = null;
img = null;
};
= url; // img对象赋值url后自动发送请求,无需插入到页面元素中去
}