Les webmasters et les opérateurs utilisent souvent des outils d'analyse de données de sites Web. Google Analytics, Baidu Statistics, Tencent Analytics, etc. sont largement utilisés. Si vous souhaitez collecter des données statistiques, vous devez d'abord collecter des données. collecte de données avec tous les principes et construire un système de collecte de données.
Analyse du principe de collecte de données
En termes simples, l'outil d'analyse statistique du site Web doit collecter le comportement des utilisateurs parcourant la cible site Web (comme ouvrir une page Web, cliquer sur un bouton, ajouter des produits au panier, etc.) et des données de comportement supplémentaires (telles que le montant de la commande généré par un comportement de commande, etc.). Les premières statistiques de sites Web ne collectaient souvent qu’un seul comportement d’utilisateur : l’ouverture d’une page. Le comportement de l'utilisateur sur la page ne peut alors pas être collecté. Cette stratégie de collecte peut répondre à des perspectives d'analyse courantes telles que l'analyse de base du trafic, l'analyse des sources, l'analyse du contenu et les attributs des visiteurs. Cependant, avec l'utilisation généralisée de la technologie ajax et des sites Web de commerce électronique, la demande d'analyse statistique des cibles de commerce électronique devient de plus en plus demandée. De plus en plus forte, cette stratégie de collecte traditionnelle est devenue au-delà de ses capacités.
Plus tard, Google a introduit de manière innovante des scripts de collecte de données personnalisables dans son produit Google Analytics Grâce à l'interface extensible définie par Google Analytics, les utilisateurs n'ont besoin que d'écrire une petite quantité de code javascript pour mettre en œuvre des événements personnalisés ainsi que le suivi et l'analyse de métriques personnalisées. . À l'heure actuelle, des produits tels que Baidu Statistics et Sogou Analytics ont copié le modèle de Google Analytics.
En fait, les principes et processus de base des deux modes de collecte de données sont les mêmes, mais ce dernier collecte plus d'informations via javascript. Jetons aujourd'hui un coup d'œil aux principes de base de la collecte de données pour divers outils de statistiques de sites Web.
Présentation du processus
Tout d'abord, le comportement de l'utilisateur déclenchera une requête http du navigateur vers la page comptée. considérez le comportement comme Ouvrir la page Web. Lorsque la page Web est ouverte, l'extrait javascript intégré dans la page sera exécuté. Les amis qui ont utilisé des outils associés doivent savoir que les outils de statistiques générales du site Web nécessiteront que les utilisateurs ajoutent un petit morceau de code javascript à la page Web. créera généralement dynamiquement une balise de script et pointera src vers un fichier js distinct (nœud vert dans la figure 1) sera demandé et exécuté par le navigateur. Ce js est souvent la véritable collection de données. scénario. Une fois la collecte de données terminée, js demandera un script de collecte de données back-end (backend dans la figure 1). Ce script est généralement un programme de script dynamique déguisé en image, qui peut être écrit en php, python ou autre côté serveur. langages.js will Les données collectées sont transmises au script back-end via les paramètres http. Le script back-end analyse les paramètres et les enregistre dans le journal d'accès dans un format fixe. En même temps, certains cookies de suivi peuvent être créés. planté dans la réponse http au client.
Ce qui précède est un processus général de collecte de données. Ce qui suit utilise Google Analytics comme exemple pour effectuer une analyse relativement détaillée de chaque étape.
Phase d'exécution du script enterré
Pour utiliser Google Analytics (ci-après dénommé GA), vous devez insérer un morceau de javascript qu'il fournit dans la page Fragment, ce fragment est souvent appelé code enterré.
où _gaq est le tableau global de GA, utilisé pour placer diverses configurations. Le format de chaque configuration est :
_gaq.push([‘Action’ , «param1’ , ‘param2’, …]);
Action spécifie l'action de configuration, suivie d'une liste de paramètres associés. Le code d'intégration par défaut fourni par GA donnera deux configurations prédéfinies. _setAccount est utilisé pour définir l'ID d'identification du site Web. Cet ID d'identification est attribué lors de l'enregistrement de GA. _trackPageview indique à GA de suivre une visite de page. Pour plus de configuration, veuillez vous référer à : https://developers.google.com/analytics/devguides/collection/gajs/. En fait, ce _gaq est utilisé comme file d'attente FIFO, et le code de configuration n'a pas besoin d'apparaître avant le code enterré. Pour plus de détails, veuillez vous référer aux instructions dans le lien ci-dessus.
En ce qui concerne cet article, le mécanisme de _gaq n'est pas au centre de l'attention. L'accent est mis sur le code de la fonction anonyme derrière lui. C'est ce que le code enterré doit vraiment faire. Le but principal de ce code est d'introduire un fichier js externe (ga.js) en créant un script via la méthode document.createElement et en pointant le src vers le ga.js correspondant selon le protocole (http ou https), et enfin ajout de cet élément Insérer dans l'arborescence DOM de la page.
Notez que ga.async = true signifie appeler de manière asynchrone des fichiers js externes, c'est-à-dire ne pas bloquer l'analyse du navigateur et s'exécuter de manière asynchrone une fois le téléchargement js externe terminé. Cet attribut est nouvellement introduit dans HTML5.
Phase d'exécution du script de collecte de données
Le script de collecte de données (ga.js) sera exécuté après avoir été demandé. Ce script effectue généralement les choses suivantes :
1. Collecter des informations via les objets javascript intégrés au navigateur, tels que le titre de la page (via document.title), référent (l'URL de saut précédente, via document.referrer), la résolution du moniteur utilisateur (via windows.screen), les informations sur les cookies (via document.cookie) et d'autres informations.
2. Analysez _gaq pour collecter les informations de configuration. Cela peut inclure le suivi des événements définis par l'utilisateur, les données commerciales (telles que les numéros de produits sur les sites Web de commerce électronique, etc.).
3. Analysez et fusionnez les données collectées au cours des deux étapes ci-dessus selon le format prédéfini.
4. Demandez un script back-end et placez les informations dans le paramètre de requête http et transférez-les au script back-end.
Le seul problème ici est l'étape 4. La méthode courante permettant à Javascript de demander des scripts back-end est ajax, mais ajax ne peut pas effectuer de requêtes inter-domaines. Ici, ga.js est exécuté dans le domaine du site Web compté et le script back-end se trouve dans un autre domaine (le script de statistiques back-end de GA est http://www.m.sbmmt.com/__utm.gif), et ajax ne fonctionne pas. Une méthode courante consiste à créer un objet Image dans un script js, à pointer l'attribut src de l'objet Image vers le script backend et à transmettre les paramètres. À ce stade, une requête inter-domaines vers le backend est implémentée. C'est pourquoi les scripts backend sont souvent déguisés en fichiers GIF. Grâce à la capture de paquets http, vous pouvez voir la requête de ga.js à __utm.gif.
Vous pouvez voir que ga.js apporte beaucoup d'informations lors de la demande de __utm.gif Par exemple, utmsr=1280×1024 est la résolution de l'écran, utmac=UA-35712773-1 est mon identifiant GA analysé à partir de _gaq etc.
Il convient de noter que __utm.gif peut non seulement être demandé lorsque le code caché est exécuté. Si le suivi des événements est configuré avec _trackEvent, ce script sera également demandé lorsque l'événement se produit.
Étant donné que ga.js a été compressé et obscurci et que sa lisibilité est très mauvaise, nous ne l'analyserons pas, j'implémenterai un script avec des fonctions similaires lors de la phase d'implémentation ultérieure.
Phase d'exécution du script backend
Le __utm.gif de GA est un script déguisé en gif. Ce type de script back-end doit généralement effectuer les tâches suivantes :
1. Analyser les informations des paramètres de la requête http.
2. Obtenez certaines informations du serveur (WebServer) que le client ne peut pas obtenir, telles que l'adresse IP du visiteur, etc.
3. Écrivez les informations dans le journal selon le format.
4. Générez une image gif vide 1×1 comme contenu de réponse et définissez le type de contenu de l'en-tête de réponse sur image/gif.
5. Définissez certaines informations de cookie requises dans l'en-tête de réponse via Set-cookie.
La raison pour laquelle les cookies sont définis est que si vous souhaitez suivre les visiteurs uniques, l'approche habituelle est que si le client ne dispose pas d'un cookie de suivi spécifié lors de la demande, un cookie globalement unique est généré conformément aux règles et implanté pour l'utilisateur, sinon Set-cookie est placé. Le cookie de suivi est obtenu pour conserver le même cookie utilisateur inchangé (voir Figure 4).
Bien que cette approche ne soit pas parfaite (par exemple, un utilisateur effaçant des cookies ou changeant de navigateur sera considéré comme deux utilisateurs), il s'agit actuellement d'une méthode largement utilisée. Notez que s'il n'est pas nécessaire de suivre le même utilisateur sur tous les sites, vous pouvez utiliser js pour installer des cookies sous le domaine du site Web comptabilisé (GA le fait. Si vous souhaitez positionner l'ensemble du réseau de manière uniforme, vous pouvez installer des cookies). dans le domaine du serveur via des scripts back-end. Ensuite (notre implémentation le fera plus tard).
Conception et mise en œuvre du système
Sur la base des principes ci-dessus, j'ai moi-même construit un système de collecte de journaux d'accès.
J'appelle ce système MyAnalytics.
Déterminer les informations collectées
Par souci de simplicité, je ne vais pas mettre en œuvre le modèle complet de collecte de données de GA, mais collecter les informations.
Enterrez le code
J'apprendrai du modèle GA, mais actuellement l'objet de configuration ne sera pas utilisé comme file d'attente FIFO.
J'utilise actuellement un script de statistiques appelé ma.js et j'ai activé le nom de domaine secondaire Analytics.codinglabs.org. Bien sûr, il y a un petit problème ici, car je n'ai pas de serveur https, donc si le code est déployé sur un site https, il y aura des problèmes, mais ignorons-le ici.
Script de statistiques front-end
J'ai écrit un script de statistiques ma.js qui n'est pas très complet mais peut compléter le travail de base :
(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://analytics.codinglabs.org/1.gif?' + args; })();
L'intégralité du script est placé dans une fonction anonyme pour s'assurer qu'il ne pollue pas l’environnement mondial. La fonction a été expliquée dans la section principe et ne sera pas décrite à nouveau. Parmi eux, 1.gif est le script back-end.
Format du journal
Le journal utilise un enregistrement par ligne, en utilisant le caractère invisible ^A (code ascii 0x01, sous Linux, il peut être saisi via ctrl + v ctrl + a, et "^A" est utilisé ci-dessous pour indiquer le caractère invisible 0x01), le format spécifique est le suivant :
Heure^AIP^ANom de domaine^AURL^ATitre de la page^AReferrer^AHaute résolution^ARésolution large^AProfondeur de couleur^ALangue^AInformations sur le client^AUser ID^Un logo de site Web
script backend
为了简单和效率考虑,我打算直接使用nginx的access_log做日志收集,不过有个问题就是nginx配置本身的逻辑表达能力有限,所以我选用了OpenResty做这个事情。OpenResty是一个基于Nginx扩展出的高性能应用开发平台,内部集成了诸多有用的模块,其中的核心是通过ngx_lua模块集成了Lua,从而在nginx配置文件中可以通过Lua来表述业务。关于这个平台我这里不做过多介绍,感兴趣的同学可以参考其官方网站http://openresty.org/,或者这里有其作者章亦春(agentzh)做的一个非常有爱的介绍OpenResty的slide: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_sw^A$u_cd^A$u_lang^A$http_user_agent^A$u_utrace^A$u_account”;
注意这里以u_开头的是我们待会会自己定义的变量,其它的是nginx内置变量。
然后是核心的两个location:
location /1.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 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_utrace $arg_utrace; set_unescape_uri $u_account $arg_account; #打开日志 log_subrequest on; #记录日志到ma.log,实际应用中最好加buffer,格式为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信号令其重新打开日志文件。
然后再/etc/crontab里加入一行:
59 * * * * root /path/to/directory/rotatelog.sh
在每个小时的59分启动这个脚本进行日志轮转操作。
测试
下面可以测试这个系统是否能正常运行了。我昨天就在我的博客中埋了相关的点,通过http抓包可以看到ma.js和1.gif已经被正确请求。
同时可以看一下1.gif的请求参数。
相关信息确实也放在了请求参数中。
然后我tail打开日志文件,然后刷新一下页面,因为没有设access log buffer, 我立即得到了一条新日志:
1351060731.360^A0.0.0.0^Awww.codinglabs.org^Ahttp://www.codinglabs.org/^ACodingLabs^A^A1024^A1280^A24^Azh-CN^AMozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4^A4d612be64366768d32e623d594e82678^AU-1-1
注意实际上原日志中的^A是不可见的,这里我用可见的^A替换为方便阅读,另外IP由于涉及隐私我替换为了0.0.0.0。
关于分析
通过上面的分析和开发可以大致理解一个网站统计的日志收集系统是如何工作的。有了这些日志,就可以进行后续的分析了。本文只注重日志收集,所以不会写太多关于分析的东西。
注意,原始日志最好尽量多的保留信息而不要做过多过滤和处理。例如上面的MyAnalytics保留了毫秒级时间戳而不是格式化后的时间,时间的格式化是后面的系统做的事而不是日志收集系统的责任。后面的系统根据原始日志可以分析出很多东西,例如通过IP库可以定位访问者的地域、user agent中可以得到访问者的操作系统、浏览器等信息,再结合复杂的分析模型,就可以做流量、来源、访客、地域、路径等分析了。当然,一般不会直接对原始日志分析,而是会将其清洗格式化后转存到其它地方,如MySQL或HBase中再做分析。
分析部分的工作有很多开源的基础设施可以使用,例如实时分析可以使用Storm,而离线分析可以使用Hadoop。当然,在日志比较小的情况下,也可以通过shell命令做一些简单的分析,例如,下面三条命令可以分别得出我的博客在今天上午8点到9点的访问量(PV),访客数(UV)和独立IP数(IP):
awk -F^A '{print $1}' ma-2012102409.log | wc -l awk -F^A '{print $12}' ma-2012102409.log | uniq | wc -l awk -F^A '{print $2}' ma-2012102409.log | uniq | wc -l
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!