Webアナリティクスツールでのログ収集のしくみ

#Webアナリティクスツールとは
Webアナリティクスツールというのは、Webページなどのアクセス解析を行うツール。
まあGoogle Analyticsとかが有名だと思う。
今回はその中のタグ受け部分を勉強用に作ったので忘れないように書いておく。

<dl>
    <dt>使用言語・フレームワーク</dt>
    <dd>・Python3</dd>
    <dd>・Flask</dd>
    <dd>・JavaScript</dd>
</dl>

#Webアナリティクスツールのタグ受け部分の仕組み
こんな感じ、Webビーコン方式と呼ばれている
![tag.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315596/0aa4bc4b-6fc9-a4f6-a174-6ff5c9ba5766.jpeg)



#タグとは
タグとはなにかというと、アクセス解析を行うWebサイトがあるとして
そこに埋め込む用のJavaScriptのことです。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset = "UTF-8">
        <title>タグ</title>
    </head>
    <body>
        <h1>タグテスト用html</h1>
        <!--タグここから-->
        <script>
            var sNew = document.createElement("script");
            sNew.async = true;
            _id = "10001";
            sNew.src  = "http://localhost:5000/entry.js?id="+_id;
            var s0 = document.getElementsByTagName('script')[0];
            s0.parentNode.insertBefore(sNew, s0);
        </script>
　　　　　<!--タグここまで-->

    </body>
</html>
```
ここでやっているのは、ざっくりいうとscriptの要素を生成して、指定のURLに非同期でリクエストを送っています。
その際識別のためにIDなどをパラメータとして付与しています。
上の図で言うと、<strong>「ブラウザからリクエスト」</strong>の部分。

#タグ受けサーバー

タグ受けサーバーというのは、リクエストを受け付けるためのサーバー。基本的にWebサーバーとやっていることは変わらない。
今回は簡単にpythonとFlaskを使用して作ってみた。

```python:tag_server.py
#! /usr/bin/env python
# -*- coding :utf-8 -*-
from flask import *
import logging
import logging.handlers
import base64
import io
import datetime

#flask app
app = Flask(__name__)

#夜中にlogが切り替わる
handler = logging.handlers.TimedRotatingFileHandler(
    filename='log/tags.log',
    when='midnight'
)
#log出力部分の設定
handler.setLevel(logging.INFO)
handler.setFormatter(logging.Formatter('[%(asctime)s] %(message)s'))
app.logger.addHandler(handler)


#entry.jsを返却するための関数
@app.route('/entry.js',methods=['GET', 'POST'])
def ajax_ddl():
    URL = 'http://localhost:5000/tag?'
    js = ""
    with open("tags.js","r",encoding="utf-8")as f:
        js_line = f.readlines()
        for i in js_line:
            js+=i.replace("¥n","")
    tmp = request.url.split("id=")
    js += 'var _imagePath = "'+URL+tmp[1]+'*" + now.getTime()+"*"+url+"*"+ref+"*"+cookie;'
    js += 'var _img = new Image(1,1);'
    js += '_img.src = _imagePath;'
    js += '_img.onload = function(){_void();}'
    resp = app.make_response(js)
    resp.mimetype = "text/JavaScript"
    return resp

#取得したlog情報を出力するし1×１のgifを返却する関数
@app.route("/tag",methods=['GET', 'POST'])
def return_gif():
    URL = request.url.replace("%2F","/");
    app.logger.info(URL)
    gif = 'R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
    gif_str = base64.b64decode(gif)
    return send_file(io.BytesIO(gif_str), mimetype='image/gif')


if __name__ == '__main__':
    app.run(host='localhost', port=5000, threaded=True,debug=True)
```
まず、ajax_ddlという関数でブラウザからのリクエストを受け取る。
図で言う所の、<strong>「JSの返却」</strong>にあたる部分である。
返却するJSはあらかじめ用意されたJSにpythonの中で生成したJSを組み合わせたものを返却している

```js:tag.js
var _void = function () { return; };
var now = new Date();
var url = window.location;
var ref = document.referrer;
url = encodeURI(url);
ref = encodeURI(ref);
if (ref == "") {
  ref = 'N/A'
}

if (url == "") {
  url = 'N/A'
}

function ckSave(){
    var date = new Date();
    term = parseInt(90);
    val = now.getTime()+Math.floor(Math.random()*10000);
    date.setTime(date.getTime()+term*24*60*60*1000);
    document.cookie = "_ck="+escape(val)+";expires="+date.toGMTString();

}
function ckLoad(){
    var r = document.cookie.split(';');
    //console.log(r);
    for(var i = 0; i < r.length; i++){
        content=r[i].split("=");
        if(content[0]==="_ck"){
            console.log(content);
            return content[1];
        }else{
            //return 0;
        }
    }
}
var result = document.cookie.indexOf('_ck');
if(result === -1){
    ckSave();
}
var cookie = ckLoad();
console.log(location.hostname);

```

このJSがブラウザにcookieを付与し必要な情報をパラメータに入れ
あらためて、リクエストを飛ばす。
これが図で言う所の、<strong>「パラメータが付与されたリクエスト」</strong>の部分。

最後に、return_gifという関数でlogのファイルへの書き込みと、1×1のgifの返却をおこなっている。
基本的にリクエストしたら、なんか返す必要があるから、昔からそうしてるみたい。
図で言う<strong>「1×1のgifを返却」</strong>のところ。

あとは、このログを集計すればPVとか、パラメータを増やせばCVとか色々なものが取れるそうです。