网站内容采集(为什么要进行网站流量数据统计分析?(一)?)

优采云 发布时间: 2022-02-09 20:25

  网站内容采集(为什么要进行网站流量数据统计分析?(一)?)

  为什么要对网站流量数据进行统计分析?

  随着大数据时代的到来,各行各业产生的数据爆炸式增长,大数据技术从之前的“虚无”成为可能。在每个行业。比如对网站流量数据进行统计分析,可以帮助网站管理员、运营商、推广者等实时获取网站流量信息,分析流量来源,网站@ > 内容、网站@网站访客特征等方面为网站分析提供数据基础。这将有助于增加网站流量,提升网站用户体验,让更多的访客落户并成为会员或客户,以更少的投入获得最大的收益。

  网站流量日志数据采集原理分析

  首先,用户的行为会触发浏览器对要统计的页面的http请求,比如打开某个网页。当网页打开时,页面中嵌入的javascript代码将被执行。

  

  嵌入是指:预先在网页中添加一小段javascript代码。此代码片段一般会动态创建脚本标签,并将 src 属性指向一个单独的 js 文件。这时这个单独的js文件(图中绿色节点)就会被浏览器请求并执行,这个js往往是真正的数据采集脚本。

  数据采集​​完成后,js会请求一个后端数据采集脚本(图中backend),一般是伪装成图片的动态脚本,js会将采集到的数据通过http参数传递给后端。脚本,后端脚本解析参数并以固定格式记录到访问日志中,并可能在http响应中为客户端植入一些cookies进行跟踪。

  设计实施

  根据原理分析,结合谷歌分析,如果要搭建自定义日志数据采集系统,需要做以下几件事:

  

  确定信息的采集

  

  确定埋藏码

  嵌入是网站分析的常用数据采集方法。核心是在需要执行数据采集的关键点植入统计代码,执行数据采集。例如,在 Google Analytics 原型的情况下,需要将其提供的 javascript 片段插入到页面中。这个片段通常被称为埋藏代码。(以谷歌的埋藏代码为例)

  

var _maq = _maq || [];

_maq.push(['_setAccount', 'UA-XXXXX-X']);

(function() {

var ma = document.createElement('script'); ma.type =

'text/javascript'; ma.async = true;

ma.src = ('https:' == document.location.protocol ?

'https://ssl' : 'http://www') + '.google-analytics.com/ma.js';

var s = document.getElementsByTagName('script')[0];

s.parentNode.insertBefore( m a, s);

})();

  其中_maq是一个全局数组,用于放置各种配置,每个配置的格式为:

  _maq.push(['Action', 'param1', 'param2', ...]);

  _maq的机制不是重点,重点是后面匿名函数的代码。这段代码的主要目的是通过document.createElement方法创建脚本,并根据协议(http或https)创建脚本,从而引入一个外部js文件(ma.js)。) 将src指向对应的ma.js,最后将这个元素插入到页面的dom树中。

  注意ma.async = true表示异步调用外部js文件,即不阻塞浏览器解析,外部js下载完成后异步执行。该属性是 HTML5 中新引入的。

  前端数据采集脚本

  请求数据采集脚本(ma.js)后,将执行。一般应做到以下几点:

  通过浏览器内置的javascript对象采集信息,例如页面标题(通过document.title)、referrer(最后一跳url,通过document.referrer)、用户显示分辨率(通过windows.screen)、cookie信息(通过document.cookie ) ) 等等以获取一些信息。解析 _maq 数组以采集配置信息。这可能包括用户自定义的事件跟踪、业务数据(如电子商务的产品编号网站等)等。将上述两步采集的数据以预定义的格式进行解析和连接(获取请求参数)。请求一个后端脚本,并在http请求参数中将信息传递给后端脚本。

  这里唯一的问题是第4步。javascript请求后端脚本的常用方法是ajax,但是ajax不能进行跨域请求。一种常用的方法是在js脚本中创建一个Image对象,将Image对象的src属性指向后端脚本并携带参数,此时就实现了跨域请求后端。这就是为什么后端脚本经常伪装成 gif 文件的原因。

  示例代码

  (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 = ' http://xxx.xxxxx.xxxxx/log.gif? ' + args;

})();

  整个脚本被放置在一个匿名函数中,以确保它不会污染全局环境。其中 log.gif 是后端脚本。

  后端脚本

  log.gif 是一个后端脚本,一个伪装成 gif 图像的脚本。后端脚本一般需要做以下事情:

  解析http请求参数以获取信息。从web服务器获取一些客户端无法获取的信息,比如guest ip等。写入信息以登录格式。生成一个 1×1 的空 gif 图片作为响应内容,并将响应头的 Content-type 设置为 image/gif。在响应头中通过 Set-cookie 设置一些需要的 cookie 信息。

  之所以设置 cookie 是因为如果要跟踪一个唯一访问者,通常的做法是根据规则生成一个全局唯一的 cookie,如果发现客户端没有指定在请求时跟踪cookie,否则放在Set-cookie中获取。到跟踪 cookie 以保持相同的用户 cookie 不变。这种做法虽然并不完美(例如,一个用户清除 cookie 或更改浏览器将被视为两个用户),但目前是一种广泛使用的方法。

  我们使用 nginx 的 access_log 进行日志采集,但是有个问题是 nginx 配置本身的逻辑表达能力有限,所以使用了 OpenResty 来做这件事。

  OpenResty 是一个基于 Nginx 扩展的高性能应用开发平台。它集成了许多有用的模块。其核心是通过ngx_lua模块对lua的集成,使得业务可以在nginx配置文件中通过lua表达出来。

  Lua 是一种用标准 C 语言编写并开源的轻量级紧凑型脚本语言,旨在嵌入到应用程序中,为应用程序提供灵活的扩展和定制能力。

  首先需要在nginx配置文件中定义日志格式:

  log_format tick

"$msec||$remote_addr||$status||$body_bytes_sent||$u_domain||$u_url|

|$u_title||$u_referrer||$u_sh||$u_sw||$u_cd||$u_lang||$http_user_ag

ent||$u_account";

  注意以u_开头的变量是我们后面自己定义的变量,其他都是nginx内置变量。然后是两个核心位置:

  location / log.gif {

#伪装成 gif 文件

default_type image/gif;

#本身关闭 access_log,通过 subrequest 记录 log

access_log off;

access_by_lua "

-- 用户跟踪 cookie 名为__utrace

local uid = ngx.var.cookie___utrace

if not uid then

-- 如果没有则生成一个跟踪 cookie,算法为

md5(时间戳+IP+客户端信息)

uid = ngx.md5(ngx.now() ..

ngx.var.remote_addr .. ngx.var.http_user_agent)

end

ngx.header['Set-Cookie'] = {'__utrace=' .. uid ..

'; path=/'}

if ngx.var.arg_domain then

-- 通过 subrequest 子请求 到/i-log 记录日志,

将参数和用户跟踪 cookie 带过去

ngx.location.capture('/i-log?' ..

ngx.var.args .. '&utrace=' .. uid)

end

";

#此请求资源本地不缓存

add_header Expires "Fri, 01 Jan 1980 00:00:00 GMT";

add_header Pragma "no-cache";

add_header Cache-Control "no-cache, max-age=0, must-

revalidate";

#返回一个 1×1 的空 gif 图片

empty_gif;

}

location /i-log {

#内部 location,不允许外部直接访问

internal;

#设置变量,注意需要 unescape,来自 ngx_set_misc 模块

set_unescape_uri $u_domain $arg_domain;

set_unescape_uri $u_url $arg_url;

set_unescape_uri $u_title $arg_title;

set_unescape_uri $u_referrer $arg_referrer;

set_unescape_uri $u_sh $arg_sh;

set_unescape_uri $u_sw $arg_sw;

set_unescape_uri $u_cd $arg_cd;

set_unescape_uri $u_lang $arg_lang;

set_unescape_uri $u_account $arg_account;

#打开日志

log_subrequest on;

#记录日志到 ma.log 格式为 tick

access_log /path/to/logs/directory/ma.log tick;

#输出空字符串

echo '';

}

  该脚本使用了很多第三方的ngxin模块(OpenResty中都收录),重点标注了注释。你不需要完全理解每一行的含义,只要你知道这个配置完成了我们提到的后端逻辑。而已。

  日志格式

  日志格式主要考虑日志分隔符。一般来说,有以下几种选择:

  固定数量的字符、制表符分隔符、空格分隔符、一个或多个其他字符、特定的开始和结束文本。

  日志分段

  日志采集系统访问日志文件随着时间的推移变大,不方便将日志管理在一个文件中。日志通常按时间段划分,例如每天一个日志或每小时一个日志。通过 crontab 定期调用一个 shell 脚本,如下所示:

  _prefix="/path/to/nginx"

time=`date +%Y%m%d%H`

mv ${_prefix}/logs/ma.log ${_prefix}/logs/ma/ma-${time}.log

kill -USR1 `cat ${_prefix}/logs/nginx.pid `

  此脚本将 ma.log 移动到指定文件夹并将其重命名为 ma-{yyyymmddhh}.log,然后向 nginx 发送 USR1 信号以重新打开日志文件。

  USR1 通常用于告诉应用重新加载配置文件,向服务器发送 USR1 信号会导致以下步骤发生:停止接受新连接,等待当前连接停止,重新加载配置文件,重新打开日志文件,重启服务器,导致变化比较顺利,不会关机。

  cat ${_prefix}/logs/nginx.pid 获取nginx的进程ID

  然后在 /etc/crontab 中添加一行:

  59 * * * * 根 /path/to/directory/rotatelog.sh

  在每小时的第 59 分钟启动脚本以进行日志轮换。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线