网站统计的基本流程
首先,用户的行为会触发浏览器对被统计页面的一个http请求,这里姑且先认为行为就是打开网页。当网页被打开,页面中的埋点javascript片段会被执行,用过相关工具的朋友应该知道,一般网站统计工具都会要求用户在网页中加入一小段javascript代码,这个代码片段一般会动态创建一个script标签,并将src指向一个单独的js文件,此时这个单独的js文件会被浏览器请求到并执行,这个js往往就是真正的数据收集脚本。数据收集完成后,js会请求一个后端的数据收集脚本,这个脚本一般是一个伪装成图片的动态脚本程序,可能由phy、python或其它服务端语言编写,js会将收集到的数据通过http参数的方式传递给后端脚本,后端脚本解析参数并按固定格式记录到访问日志,同时可能会在http响应中给客户端种植一些用于追踪的cookie。
数据收集具体细节
- 通过浏览器内置javascript对象收集信息,如页面title(通过document.title)、referrer(上一跳url,通过document.referrer)【referrer 属性可返回载入当前文档的文档的 URL】、用户显示器分辨率(通过windows.screen)、cookie信息(通过document.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 = document.createElement('script'); ma.type = 'text/javascript'; ma.async = true;
ma.src = ('https:' == document.location.protocol ? 'https://analytics' : 'http://analytics') + '.codinglabs.org/ma.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ma, s);
})();
</script>
前端统计脚本
(function () {
var params = {};
//Document对象数据 if(document) {
params.domain = document.domain || '';
params.url = document.URL || '';
params.title = document.title || '';
params.referrer = document.referrer || '';
}
//Window对象数据 if(window && window.screen) {
params.sh = window.screen.height || 0;
params.sw = window.screen.width || 0;
params.cd = window.screen.colorDepth || 0;
}
//navigator对象数据 if(navigator) {
params.lang = navigator.language || '';
}
//解析_maq配置 if(_maq) {
for(var i in _maq) {
switch(_maq[i][0]) {
case '_setAccount':
params.account = _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);
img.src = '后端脚本地址?' + args;
})();
名词解释
流量的意思包含了很多:页面浏览数(PV)、独立访问者数量(UV)、IP、页面停留时间、页面操作时间、页面访问次数、按钮点击次数、文件下载次数等。
埋点实例脚本
- 借助新浪IP地址库,显示本地城市名称:
<script src="http://int.dpool.sina.com.cn/iplookup/iplookup.php?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://www.coding123.net/getip.ashx?js=1"></script>
- 获取用户的访问开始时间、访问结束时间、以及用户与网站的交互时间(当用户在网页无操作时间超过30秒,理解为离开网页),其中无操作包括:鼠标点击、移动、滑轮无操作,键盘无按键操作。
var start = new Date();
var strStart = start.getFullYear()+"-"+(start.getMonth()+1)+"-"+start.getDate()+" "+
start.getHours()+":"+start.getMinutes()+":"+start.getSeconds();
var len = 0;
var end;
var status = "in";
var second = 30;
function revive(){
if(status == "out"){
start = new Date();
status = "in";
}
second = 30;
}
window.setInterval(function(){
second -= 1;
if(0 == second){
end = new Date();
len += (end.getTime() - start.getTime())/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();
});
window.onbeforeunload = function(){
end = new Date();
var strEnd = end.getFullYear()+"-"+(end.getMonth()+1)+"-"+end.getDate()+" "+
end.getHours()+":"+end.getMinutes()+":"+end.getSeconds();
len += (end.getTime() - start.getTime())/1000;
var img = new Image();
img.src = contextPath + "behavior?stayTime=" + len + "&strStart" + strStart + "&lastDate=" + strEnd;
};
- 获取点击按钮
<a onclick="return getid(this.id)"> 按钮</a>
function getid(id) {
var img = new Image();
img.src = contextPath + "button?id=" + id;
}
获取搜索来源
判断从哪个搜索工具找到你的网站,document.referrer(上级URL),这个可以获取到你上级页面,如果看到上级URL里面包含baidu,就可以粗略的判断是从百度访问的页面。
创建img
function sendUrl(url) {
let img = new Image(); // 创建一个img对象
let key = 'project_log_' // 为本次数据请求创建一个唯一id
+ Math.floor(Math.random() * 2147483648).toString(36);
window[key] = img; // 用一个数组维护img对象
img.onload = img.onerror = img.onabort = function () {
img.onload = img.onerror = img.onabort = null; // 清除img元素
window[key] = null;
img = null;
};
img.src = url; // img对象赋值url后自动发送请求,无需插入到页面元素中去
}