前端三種埋點


埋點到底是什么呢?

引用自百科的原話是,埋點分析網站分析的一種常用的數據采集方法。因此其本質是分析,但是靠什么分析呢?

靠埋點得到的數據。通俗來講,就是當我想要在某個產品上得到用戶的一些行為數據用來分析,就可以用埋點了。舉個栗子,A用戶把某本書加到了自己的書架了,我可以通過該用戶書架的書的類型,由此分析該用戶的閱讀偏好,更深一步,通過對用戶偏好的判斷,我可以自動像用戶推薦同類型的書,或者可以根據用戶加入書架的時間,判斷用戶的碎片時間,在此時間段,可以定點向用戶推送一些消息等。

我們可以看出,充分的埋點數據,有助於准確的分析用戶的行為,為產品的調整提供方向。

怎么埋點呢?

要想知道埋點的方法,首先要了解埋點的分類,目前埋點主要分為三大類,分別是:

1.代碼埋點

2.無埋點

3.可視化埋點(可認為是無埋點的一種)

已經知道了埋點的分類了,那么具體怎么實施呢,因其依靠數據,因此其步驟有三:

1.獲取數據

2.展示數據

3.分析數據

充分准確的埋點是第一步,對后續的展示及分析都有重要的意義,因此本文重點介紹該方面。

埋點類別詳解

1. 代碼埋點

優點:監控用戶行為,監測數據准確

缺點:工作量大,需要手動在需要埋點的地方進行埋點,因此需要侵入業務代碼,比如點擊事件的回調函數、頁面的生命周期、ajax回調等。

常用代碼埋點類型分兩類,分別為命令式、聲明式,可查看如下舉例。

//命令式
$('button').click(()=>{
    record(data);
});//聲明式
<button data-record = '{key:"recordTest",data:"recordData"}'>記錄</button>
復制代碼

命令式埋點:在一些事件操作的回調函數中進行埋點,埋點的數據和方法可能多種多樣的,比如圖片上帶數據,ajax發送數據等。

聲明式埋點:將埋點信息封裝在自定義屬性中,通過sdk識別自定義屬性然后獲取埋點數據。

2. 無埋點

優點:不需要關注埋點邏輯

缺點:給數據傳輸增加壓力、無法定制

無埋點統計數據基本流程

 

通常,當頁面打開時,頁面中的埋點js片段會被執行,這段js代碼會異步加載一個js文件,該文件就是無埋點的sdk,會被瀏覽器請求到並執行,通過該腳本進行數據收集,當數據收集完成后,可以利用一些方法將數據傳遞給后端進行收集整理。

無埋點sdk執行階段

<script type="text/javascript">var _bury = _bury||[];
_bury.push(["_testData","網站標識"]);
(function(){
    var jsnode = document.createElement('script');
    jsnode.type='text/javascript';
    jsnode.async=true;
     //這里填入js sdk鏈接
    jsnode.src= 'xxxxxxx/bury_test.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(jsnode,s);
})</script>

通過在頁面或者基礎腳本中集成這段代碼,可以在對應的頁面上引入我們的bury_test腳本,而bury_test腳本就是我們的埋點sdk。

埋點sdk

(function() {
  var buryData = {};
  //常用信息
  if (document) {
    //域名
    buryData.domain = document.domain || '';
    //標題
    buryData.title = document.title || '';
    //訪問來源
    buryData.referrer = document.referrer || '';
    //分辨率
    buryData.sw = window.screen.width || 0;
    buryData.sh = window.screen.height || 0;
    //設備信息
    buryData.lang = navigator.language || '';
    buryData.ua = navigator.userAgent || '';
    //頁面加載時間
    buryData.loadT = window.performance.timing.domContentLoadedEventEnd - window.performance.timing.navigationStart || 0;
  }
  //整理埋點數據
  var arg = [];
  if (buryData) {
    for (var i in buryData) {
      arg.push(encodeURIComponent(i) + '=' + encodeURIComponent(buryData[i]));
    }
  }
  var args = arg.join('&');
})

通過以上方法,可以獲取一些基本的頁面數據,更多詳細的數據,可以根據具體的業務需求進行添加。

如何將采集到的數據進行上報呢,需要根據具體的情況來分析了,如果沒有跨域的話,最簡單的當然是ajax了。但是很多sdk都涉及到跨域了,目前主流的一種方法是用js腳本創建Image對象,將image的src指向后端腳本,並將數據拼接上。

3. 可視化埋點

優點:通過集成sdk,運營可自主選擇,操作便捷。

缺點:無法定制詳細的業務數據,比如 金額、商品數量等,該類數據需要實時變化;

需要統一規范,無法用在不同的設備上,比如某些特殊的設備imei並不能識別。

可視化埋點與代碼埋點的對比

 

 

目前很多商用軟件比如Mixpanel、TalkingData、諸葛IO、騰訊MTA等都可以用來可視化埋點,用戶僅需要點擊想要監測的元素,然后對該埋點起個對應的名字,並給個編號,就進行了埋點。

可視化埋點的核心方案是利用xpath,是在xml文檔中查找信息的語言,如下圖所示

 

 

通過上圖方法,得到的xpath為//*[@id="1"]/div/div[2]/p[1] 如果將其換做dom的選擇器,則為:#1>div>div:nth-of-type(2)>p:nth-of-type(1),由此,可以定位到固定的DOM節點。

如何獲取xpath呢,這里可以提供一種方法可供參考:

var getPath = function(elem) {
  if (elem.id != '') {
    return '//*[@id=\"' + elem.id + '\"]';
  }
  if (elem == document.body) {
    return '/html/' + elem.tagName.toLowerCase();
  }
  var index = 1,
    siblings = elem.parentNode.childNodes;
  for (var i = 0, len = siblings.length; i < len; i++) {
    var sibling = siblings[i];
    if (sibling == elem) {
      return arguments.callee(elem.parentNode) + '/' + elem.tagName.toLowerCase() + '[' + (index) + ']';
    } else if (sibling.nodeType == 1 && sibling.tagName == elem.tagName) {
      index++;
    }
  }
}

通過上述方法,當我們點擊某個元素時,將觸發的元素event.target傳入,即可得到完整的xpath。

三種埋點的區別

以百度舉例: 當用戶點擊百度一下的時候,無埋點和可視化埋點可以獲取的信息有某個時刻、某個設備進行了一次搜索,甚至可以獲得部分搜索信息等,但是用戶在輸入搜索信息時,是否進行了修改、反復刪除重新輸入幾次等深度的業務信息,無埋點和可視化埋點是統計不到的,則需要代碼埋點。

App可視化埋點方案

背景

目前統計已經是一個產品常見的需求,尤其在業務模式探索的前期,埋點功能更是必不可少的功能,下面將介紹最簡單的app全埋點方案!

什么是數據埋點

數據埋點是一般項目采用統計UV,PV,Action,Time等一系列的數據信息,對特定用戶行為或事件進行捕獲、處理和發送的相關技術及其實施過程。

為什么要數據埋點

產品或運營分析人員,基於埋點數據分析需要,對用戶行為的每一個事件進行埋點布置,並通過SDK上報埋點的數據結果,進行分析,並進一步優化產品或指導運營。

數據埋點包括哪些

這里有我之前寫的一篇文章App優質精准的用戶行為統計和日志打撈方案

地址:http://blog.csdn.net/sk719887916/article/details/50931485

數據埋點采集模式

自動埋點

App通過代理,調用Sdk相關API,進行的將數據埋點上報的模式.

無痕埋點

無需通過專門提供代理類,直接由sdk提供相關接口,或者通過編譯工具,預編譯替換代碼等,直接由sdk全部負責采集上報

可視化埋點

可視化埋點指 前端或者app端基於dom 元素和控件所精准自動埋點的上報的方案。

對比分析:

自動埋點:

缺點:
1 開發人員工作量大,需對業務提供唯一的ID,來區分每一個業務,無論是否提供sdk代理,業務開發人員至少需要多次調用sdk相關API.

2 業務人員和產品溝通成本提高,需要對具體業務制定相關的業務標識,以便於產品分析和統計

優點:

產品運營工作量少,對照業務映射表,就能分析出還原相關業務場景, 數據比較精細,無需大量的加工和處理。

無痕埋點

缺點:

1 sdk開發人員需提供一套無痕埋點技術成品,包括能正確獲取PV,UV,ACtion,TIme等多項統計指標。前期技術投入大。

2 數據量大,需后端落地進行大量處理,並由產品進行自我還原業務員場景。 無論采用智能系統平台,還是通過原生的數據庫查詢數據,都是一種大量的分析精力。

優點:

1 開發人員工作量小,無需對業務標識進行唯一區分,由sdk自動進行生成,ID規則由sdk和產品進行約定。減少業務人員的溝通成本和使用步驟。

2 數據量全面,覆蓋面廣,產品可按需進行分析。做到毫無遺漏。

3 支持動態頁面和局部動效的統計。

可視化埋點

優點:

1 相對數據量而言
相比較於無埋點相而言對較低,但是這個可視化元素的識別技術是客戶端或者前端所要實現的,唯一id生成也無需客戶端去自定義規則,這套生成規則由相關產品在自動化工具的情況下生成配置表,下發到客戶端,再由客戶端按坑就班到相關界面去實現。

2 數據量相對精確

缺點:

1 可視化工具的平台的搭建,靜態頁面的元素識別都需要額外開發。
2 動態效果可能會遺漏。

實現方案:

埋點需求可參考我之前的文章:

App優質精准的用戶行為統計和日志打撈方案

App打造自定義的統計SDK

自動埋點實際上也是,提供一個base類,由業務類繼承base類,在base里面做相關統計api調用,
可參考我的github:https://github.com/Tamicer/SkyMonitoring

核心實現:

以android作為列子:

提供自動遍歷元素 並能撲捉點擊的控件的activity, 並能在生命周期統計pv的打開和關閉,調用我開源的SkyMonitoring的對應的api.

復寫dispatchTouchEvent(MotionEvent ev) 事件函數,確定被點擊的view的相關位置,並生成唯一的ID,企業級app都是從服務器下發對應的ID,對應頁面去調用埋點sdk Api,實現事件行為TcStatInterface.initEvent(path.viewTree);。

這個path就是view的路徑,頁面的深度路徑,包括打開和關閉sdk在SkyMonitoring中已能自動獲取。

本次demo是id生成規則是按照 :包名+ Activity+ Viewgroup+ Layout+ view + View index + viewID實現的。

業務直接去繼承TamicActivity即可,就能去實現所有可視化view的埋點功能。

代碼如下:

 “`
public abstract class TamicActivity extends AppCompatActivity {

private int statusBarHeight;
View rootView;
String rootViewTree;
String bigDataPrefix;
String bigDataIngorePrefix;
String bigDataEventPrefix;
private String TAG  = "LYK";

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    //獲取到根節點的view
    rootView = getWindow().getDecorView();
    //控件在視圖樹上的根路徑
    rootViewTree = getPackageName() + "." + getClass().getSimpleName();
    //前綴名 bigData
    bigDataPrefix = "Tamic_test";
    //前綴名 bigData_
    bigDataIngorePrefix = bigDataPrefix + "";
    //前綴名 bigdata_ignore
    bigDataEventPrefix =  bigDataIngorePrefix +"Igmore";
}

@Override
protected void onResume() {
    super.onResume();

    TcStatInterface.recordPageStart(TamicActivity.this);
}

@Override
protected void onPause() {
    super.onPause();

    TcStatInterface.recordPageEnd();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    // APP退出
    TcStatInterface.recordAppEnd();

}


@Override
public boolean dispatchTouchEvent(MotionEvent ev) {

    if(ev.getAction() == MotionEvent.ACTION_DOWN){
        ViewPath path = findClickView(ev);
        if(path != null) {
            Log.e(TAG, "path -->" + path.viewTree);
            TcStatInterface.initEvent(path.viewTree);
        }
    }
    return super.dispatchTouchEvent(ev);
}

private ViewPath findClickView(MotionEvent ev) {
    Log.e(TAG, "bigdata-->findClickView");
    ViewPath clickView = new ViewPath(rootView, rootViewTree);
    return searchClickView(clickView, ev, 0);
}


private ViewPath searchClickView(ViewPath myView, MotionEvent event, int index) {
    ViewPath clickView = null;
    View view = myView.view;
    if (isInView(view, event)) {   
        myView.level++;
        if (myView.level == 2 && !"LinearLayout".equals(view.getClass().getSimpleName())) {
            myView.filterLevelCount++;
        }
        if (myView.level > myView.filterLevelCount) {
            myView.viewTree = myView.viewTree + "." + view.getClass().getSimpleName() + "[" + index + "]";
        }
        Log.i(TAG, "bigdata-->tag = " + view.getTag());
        if (view.getTag() != null) {
            // 主動標記不需要統計時,不進行自動統計
            String tag = view.getTag().toString();
            if (tag.startsWith(bigDataIngorePrefix)) {
                return null;
            } else if (tag.startsWith(bigDataPrefix)) {
                if (tag.startsWith(bigDataEventPrefix)) {
                    myView.specifyTag = tag.replace(bigDataEventPrefix, "");
                }
                return myView;
            }
        }
        if (view instanceof ViewGroup) {   
            if (view instanceof AbsListView) {
                Log.i(TAG, "bigdata-->AbsListView ");
                return null;
            }
            ViewGroup group = (ViewGroup) view;
            int childCount = group.getChildCount();
            if (childCount == 0) {
                return myView;
            }
            for (int i = childCount - 1; i >= 0; i--) {
                myView.view = group.getChildAt(i);
                clickView = searchClickView(myView, event, i);
                if (clickView != null) {
                    return clickView;
                }
            }
        } else {
            clickView = myView;
        }
    }
    return clickView;
}

private boolean isInView(View view, MotionEvent event) {
    if (view == null || view.getVisibility() != View.VISIBLE) {
        return false;
    }
    int clickX = (int) event.getRawX();
    int clickY = (int) event.getRawY();
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    int x = location[0];
    int y = location[1];
    int width = view.getWidth();
    int height = view.getHeight();
    return clickX > x && clickX < (x + width) && clickY > y && clickY < (y + height);
}

}

App項目集成使用,初始化url和相關統計配置字典,這個字典可以從服務器下發下來,我本次只是通過簡單的本地文件做實踐。

public class StatAppliation extends Application {

@Override
public void onCreate() {
    super.onCreate();
    // you app id
    int appId = 21212;
    // assets
    String fileName = "my_statconfig.json";
    String url = "https://github.com/Tamicer/TamicAppMonitoring";
    // init statSdk
    TcStatInterface.initialize(this, appId, "you app chanel", fileName);
    TcStatInterface.setUrl(url);
    TcStatInterface.setUploadPolicy(TcStatInterface.UploadPolicy.UPLOAD_POLICY_DEVELOPMENT, TcStatInterface.UPLOAD_TIME_ONE);
 }
}

可視化也可以通過aop插樁實現,但是實現起來對代碼的入侵性太高,這里不做介紹。

aop插樁對碎片化fragment支持比較好。對這塊的介紹可看我以前在公眾號推送的一篇文章
AOP編程之AspectJ實戰實現數據無痕埋點

可參考:
https://www.baidu.com/link?url=FniQOFyj1pd6O5Fz6viRMN3ZgexIKAk7SQ08EgpBU9cHHMszPlm2jRXJ21mkomtY&wd=&eqid=ffc87acf0005fd18000000045a5d98dd

可參考項目地址:

github:https://github.com/Tamicer/TamicAppMonitoring


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM