宝哥软件园

网站统计中数据收集的原理与实现

编辑:宝哥软件园 来源:互联网 时间:2021-11-16

网站统计分析工具是站长和运营商经常使用的工具,如谷歌分析、百度统计、腾讯分析等。所有这些统计分析工具的第一步是收集网站访问数据。目前主流的数据采集方式基本都是基于javascript的。本文将简要分析这种数据采集的原理,并逐步构建一个实用的数据采集系统。数据收集原理分析简单来说,网站统计分析工具需要收集用户浏览目标网站的行为(如打开网页、点击按钮、向购物车添加商品等)。)和行为的附加数据(例如由下单行为产生的订单量等)。).早期的网站统计往往只收集到一种用户行为:页面打开。那么用户在页面中的行为就无法被收集。这种收集策略可以满足流量分析、来源分析、内容分析、访问者属性等基本分析视角。然而,随着ajax技术的广泛使用和电子商务网站对电子商务目标统计分析需求的不断增加,这种传统的收集策略已经超出了它的能力范围。后来,谷歌创新性地在其产品谷歌分析中引入了可定制的数据收集脚本。用户可以通过Google Analysis定义的可扩展接口,编写少量javascript代码,跟踪分析自定义事件和自定义指标。目前,百度统计、搜狗分析等产品都复制了谷歌分析模型。实际上,这两种数据收集模式的基本原理和过程是相同的,但后者通过javascript收集更多的信息。先来看看各种网站统计工具的数据收集基本原理。概述首先,通过一张图片来看数据收集的基本过程。1

1.网站统计数据收集的基本流程首先,用户的行为会触发浏览器对统计页面的http请求。让我们考虑一下,行为是打开网页。当网页打开时,网页中嵌入的javascript片段将被执行。用过相关工具的朋友应该知道,一般的网站统计工具都会要求用户在网页上添加一段简短的javascript代码。这个代码片段通常会动态地创建一个脚本标签,并将src指向一个单独的js文件。此时,浏览器将请求并执行这个单独的js文件(图1中的绿色节点),这个js通常是真正的数据收集脚本。数据采集完成后,js会请求一个后端数据采集脚本(图1中的后端),一般是伪装成图片的动态脚本,可能是用php、python或者其他服务器语言编写的。js将以http参数的形式将收集的数据传递给后端脚本,后端脚本将解析这些参数,并以固定的格式将它们记录到访问日志中。同时,一些用于跟踪的cookie可能会在http响应中植入到客户端。以上是数据收集的大致过程,下面以Google分析为例,对各个阶段进行相对详细的分析。如果要在嵌入式脚本的执行阶段使用Google Analytics(以下简称GA),需要在页面中插入它提供的一个javascript片段,这通常被称为嵌入式代码。以下是放在我博客里的Google Analytics埋藏点代码截图:2

图2。Google Analytics埋藏点代码,其中_gaq是GA的全局数组,用于放置各种配置。每个配置的格式如下:复制代码如下: _ gaq.push (['action ',' param1 ',' param2 ',]);操作指定配置操作,后跟相关参数列表。GA给出的默认埋点编码会给出两种预设配置。_setAccount用于设置网站ID,注册GA时分配。_trackPageview告诉GA跟踪页面访问。更多配置请参见:https://developers . Google.com/analytics/dev guides/collection/gajs/了解。实际上,这个_gaq是作为一个FIFO队列使用的,配置代码不需要出现在隐藏代码之前。详情请参考上述链接的描述。就本文而言,_gaq的机制并不是重点,而是其背后匿名函数的代码,这才是被埋没的代码真正需要做的。这段代码的主要目的是引入一个外部js文件(ga.js),通过document.createElement方法创建一个脚本,根据协议(http或https)将src指向对应的ga.js,最后将这个元素插入到页面的dom树中。请注意,ga.async=true表示异步调用外部js文件,也就是说,浏览器的解析不会被阻塞,在下载外部js后异步执行。这个属性是HTML5中新引入的。在数据收集脚本执行阶段,数据收集脚本(ga.js)将在被请求后执行。这个脚本一般需要做以下几件事:1。通过浏览器内置的javascript对象收集信息,如页面标题(通过document.title)、referrer(通过document.referrer,通过前面的url)、用户显示分辨率(通过windows.screen)、cookie信息(通过document.cookie)。2.解析由_gaq收集的配置信息。这可能包括用户定义的事件跟踪、商业数据(如电子商务网站的商品编号等)。),等等。3.按照预先定义的格式,对以上两个步骤收集的数据进行分析和拼接。4.请求一个后端脚本,并在http request参数中携带信息给后端脚本。这里唯一的问题是第四步。ajax是javascript请求后端脚本的常用方法,但是ajax不能跨域请求。这里GA.js是在要统计的网站的域中执行的,而后端脚本在另一个域中(GA的后端统计脚本是http://www . Google-analytics.com/_ _ UTM . gif),所以ajax不会工作。常见的方法是js脚本创建一个Image对象,Image对象的src属性指向后端脚本并携带参数,此时实现跨域请求后端。这就是为什么后端脚本通常伪装成gif文件。可以通过http capture: 3看到ga.js对__utm.gif的请求。

图3。后端脚本请求的http包显示,GA.js在请求__utm.gif时带来了很多信息,例如,utmsr=12801024是屏幕分辨率,utmac=UA-35712773-1是我在_gaq中解析的ga ID等等。值得注意的是,只有在执行隐藏代码时,才可能不请求__utm.gif。如果使用_trackEvent配置了事件跟踪,当事件发生时,也会请求该脚本。因为ga.js被压缩混淆了,可读性很差,我们就不分析了。我将在后期实现阶段实现一个具有类似功能的脚本。后端脚本执行阶段GA的__utm.gif是伪装成gif的脚本。这种后端脚本通常需要完成以下几件事:1。解析http请求参数的消息。2.从WebServer获取一些客户端无法获取的信息,例如来宾ip。3.根据格式将信息写入日志。5.生成11的空gif图片作为响应内容,并将响应头的内容类型设置为图像/gif。5.通过Set-cookie在响应头中设置一些必需的cookie信息。设置cookie的原因是,如果您想要跟踪唯一的访问者,通常的做法是根据规则生成一个全局唯一的cookie,如果发现客户端在请求时没有指定的跟踪cookie,则为用户植入它,否则,将获得的跟踪cookie放在Set-cookie中,以保持同一用户的cookie不变(见图4)。4

图4。通过cookies跟踪唯一用户的原则。虽然这种做法并不完美(比如用户清除cookies或者更换浏览器就会被认为是两个用户),但这是目前广泛使用的手段。注意,如果没有对同一用户需求的跨站点跟踪,可以通过js将cookies种植在被统计站点的域下(GA是这样做的),如果要对整个网络进行统一定位,可以通过后端脚本将cookies种植在服务器域下(我们的实现稍后会这样做)。根据以上原则,我自己构建了一个访问日志收集系统。一般来说,建立这个系统应该做以下几件事:5

图5。访问数据收集系统工作分解确定收集的信息为简单起见,我不打算实现GA的完整数据收集模型,而是收集以下信息。名称路径备注访问时间网络服务器nginx $ msec IP网络服务器nginx $ remote _ addr域名Javascript document . domainurljavascriptdocument . URL页面标题javascriptdocument.title解析JAVAScript。ipt window . screen . height width color depth hreferrer JavaScript document . referrer browse client web server enginex $ http _ user _ agent client language JavaScript。iptnavigator . language visitor id cookie网站id javascript自定义对象埋码埋码我会借鉴ga的模式,但目前我不会使用配置对象作为FIFO队列。一个隐藏代码的模板如下:复制代码如下: Script Type=' text/JavaScript ' var _ maq=_ maq | |[];_maq.push(['_setAccount ','网站id ']);(function(){ var ma=document . create element(' script ');ma . type=' text/JavaScript ';ma.async=真;ma . src=(' https : '==document . location . protocol?https://analytics ' : ' http://analytics ')' . coding labs . org/ma . js ';var s=document . getelementsbytagname(' script ')[0];s.parentNode.insertBefore(ma,s);})();/script在这里,我启用了二级域名analytics.codinglabs.org,而统计脚本的名称是ma.js.当然,这里有一点小问题,因为我没有https服务器,所以如果一个https站点部署代码,就会有问题,但是这里我们忽略它。我写了一个统计脚本ma.js,虽然不完美但是可以完成基础工作:复制的代码如下:(function(){ var params={ };//Document对象数据if(Document){ params . domain=Document . domain | | ' ';params.url=文档。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 . color depth | | 0;} //navigator对象数据if(navigator){ params . lang=navigator . lang | | ' ';}//parse _maq配置if(_ maq){ for(var I in _ maq){ switch(_ maq[I][0]){ case ' _ set account ' : params。account=_ maq[I][1];打破;default: break} } }//拼接参数字符串var args=for(var i in params) { if(args!=' '){ args=' ';} args=I '=' encodeURIComponent(params[I]);}//通过Image对象请求后端脚本varig=new Image(1,1);img . src=' http://analytics . coding labs . org/1 . gif '?args})();整个脚本被放在一个匿名函数中,以确保它不会污染全球环境。原理部分已经解释过了,不再赘述。1.gif是后端脚本。日志格式日志采用每行一条记录,采用不可见字符a (ascii码001,Linux中ctrl v ctrl a可以输入,下面不可见字符001使用“a”)。格式如下:时间^AIP^A域名^AURL^A页面标题一个引荐者一个高分辨率一个广色深一种语言一个客户端信息一个用户标识一个网站标识后端脚本为了简单高效,我打算直接使用nginx access_log进行日志收集,但是有一个问题就是nginx配置本身逻辑表达能力有限,所以我选择了它。OpenResty是一个基于nginx的高性能应用开发平台,里面集成了很多有用的模块,其核心是通过ngx_lua模块进行lua集成,这样就可以在Nginx配置文件中通过Lua来表达服务。这个平台我在这里就不多介绍了。感兴趣的同学可以参考它的官方网站,http://openresty.org/.或者这里有一个非常可爱的介绍,由它的作者,代理人:OpenResty的http://agentzh.org/misc/slides/ngx-openresty-ecosystem/。关于ngx_lua,请参考https://github.com/chaoslawful/lua-nginx-module.

首先需要在nginx的配置文件中定义日志格式:复制代码如下: log _ format tick ' $ msec a $ remote _ addr a $ u _ domain a $ u _ URL a $ u _ title a $ u _ referrer a $ u _ sh a $ u注意,这里以u _开头的变量是我们后面自己定义的变量,其他的是nginx的内置变量。然后核心中有两个位置:复制代码如下:location /1.gif {#伪装成gif文件default _ type image/gif;#自己关闭access_log,通过子请求记录log access _ log offaccess _ by _ Lua '-用户跟踪cookie的名称是_ _ utrace本地uid=ngx.var.cookie _ _ _ utrace如果不是uid,则生成一个跟踪cookie。算法是md5(时间戳IP客户端信息)uid=ngx.md5 (ngx.now().ngx.var.remote _ addr.ngx . var . http _ user _ agent)endngx . header[' set-cookie ']={ ' _ _ ut race='.uid。Path=/'}如果ngx.var.arg _ domain,则将日志从subrequest记录到/i-log,并将参数和用户跟踪cookie带到ngx . location . capture(/I-log?' .' ngx.var.args . 'utrace='.uid)end ';# add _ header expires' fri,01 jan1980 00:00:00 GMT '没有为此请求缓存;add_header Pragma“无缓存”;add_header Cache-Control '无缓存,最大年龄=0,必须重新验证';#返回11的空gif图片empty _ gif} location /i-log {#内部位置,不允许外部直接访问内部;#设置变量,注意需要转义set _ escape _ uri $ u _ domain $ arg _ domain;set _ une scape _ uri $ u _ URL $ arg _ URL;set _ une scape _ uri $ u _ title $ arg _ title;set _ une scape _ uri $ u _ referrer $ arg _ referrer;set _ unescape _ uri $ u _ sh $ arg _ shset _ unescape _ uri $ u _ sw $ arg _ swset _ unescape _ uri $ u _ cd $ arg _ cdset _ une scape _ uri $ u _ lang $ arg _ lang;set _ une scape _ uri $ u _ ut race $ arg _ ut race;set _ une scape _ uri $ u _ account $ arg _ account;#打开上的log log _ subrequest#记录日志到ma.log在实际应用中,最好以tick access _ log/path/to/logs/directory/ma . log tick的格式添加缓冲区;#输出空字符串回声“”;}要完整解释这个脚本的每个细节有点超出了本文的范围,使用了许多第三方ngxin模块(都包含在OpenResty中)。我已经用注释标注了重点,不需要完全理解每一行的意思,只知道这个配置完成了我们在原理部分提到的后端逻辑。日志轮换真正的日志收集系统会访问大量的日志,时间长了文件会变得很大,一个文件管理日志不方便。因此,通常需要按时间段划分日志,例如,每天或每小时一个日志。在这里,为了明显的效果,我每小时砍一根木头。我通过crontab定期调用shell脚本来实现这一点。shell脚本如下:复制代码如下: _ prefix='/path/to/nginx ' time=` date % y % m % d % h ` mv $ { _ prefix }/log/ma . log $ { _ prefix }/log/ma/ma-$ { time }。Cat $ {_ prefix}/logs/nginx.pid `此脚本将ma.log移动到指定文件夹,并将其重命名为ma-{ yymmdhh }。日志,然后向nginx发送USR1信号以重新打开日志文件。然后在/etc/crontab中添加一行:复制代码如下: 59 * * * * root/path/to/directory/rotatelog . sh每小时59分钟启动这个脚本来循环日志。下面的测试可以测试系统能否正常运行。昨天我在博客里埋了相关的点,可以看到ma.js和1.gif已经被http: 6正确请求了。

图6。ma.js和1.gif的http包分析请求,同时可以看看1.gif的请求参数:7

图7中关于请求参数的信息。1.gif确实放在请求参数中。然后我尾部打开日志文件并刷新页面,因为没有访问日志缓冲区。我立即得到了一个新的日志:副本代码如下: 1351060731.360 a 0 . 0 . 0 . 0 awww.codinglabs.org a http://www.codinglabs.org/acodinglabs a a 1024 a 1280 a24 azh。MAC OS x 10 _ 8 _ 2)apple WebKit/537.4(khtml,喜欢壁虎)chrome/22 . 0 . 1229 . 94 safari/537.4 a4d 612 be 64366768d 32 e 623d 594 e 82678 au-1-1注意原始日志。看日志轮换目录,之前已经埋了一些点,所以生成了很多轮换文件:8

图8。轮换日志分析通过以上的分析和开发,我们可以大致了解一个网站统计日志收集系统是如何工作的。有了这些日志,你就可以进行后续的分析。本文只关注日志收集,所以不会写太多关于分析的内容。请注意,最好在原始日志中保留尽可能多的信息,而不是过滤和处理太多信息。例如,MyAnalytics保留毫秒时间戳,而不是格式化时间,时间的格式化是后一个系统的责任,而不是日志收集系统的责任。后者系统可以根据原始日志分析很多东西,比如可以通过IP库定位访客所在区域,从用户代理获取访客的操作系统、浏览器等信息,结合复杂的分析模型分析流量、来源、访客、区域和路径。当然,原始日志不会被直接分析,而是会被清理和格式化,并转移到其他地方,比如MySQL或HBase进行分析。有许多用于分析的开源基础设施,例如用于实时分析的Storm和用于离线分析的Hadoop。当然,当日志比较小时,也可以通过shell命令做一些简单的分析。比如下面三个命令可以分别得到我今天早上8: 00到9: 00的博客访问量(PV)。访客数(UV)和独立IP数(IP):复制代码如下: awk-f a ' { print $ 1 } ' ma-2012102409 . log | WC-l awk-f a ' { print $ 12 } ' ma-2012102409 . log . WC-l awk-f a ' { print $ 2 } ' ma-2012102409 . log | uniq | WC-l其他有趣的事情朋友可以挖掘一下参考GA:https://developers . Google.com/analytics/devguides/collection/gajs/一篇关于实现nginx日志收集的文章:http://blog.linezing.com/2011/11/.使用Nginx保存日志。请参考nginx。http://wiki.nginx.org/MainOpenResty的官方网站是:http://openresty . org GX _ Lua。请参考https://github.com/chaoslawful/lua-nginx-module.本文使用Chrome浏览器开发工具进行http捕获,使用Xmind进行思维导图,使用Tikz PGF进行流程和结构图。

更多资讯
游戏推荐
更多+