GA google_analysis数据埋点使用学习记录(GTM)


半个多月之后。。。
现在完成了GTM的埋点需求回来把文章写完,对整个GA和GTM的机制好像更理解了一点。
GA和GTM有关又无关。

GA就好比一个简易版的帮助你分析网站数据的分析网站,你用GA提供的js工具包(analysis.js)提供的ga方法向GA网站发送数据。
而GTM又称 代码管理工具(x),我觉得它更像是 第三方代码管理工具。

打个比方,要是除了GA,你还想让一个其他的网站 W 想要记录网站信息,这时候你又得下载W提供的工具包,辛辛苦苦把同样的数据手动发给W。
(假设你的网站是电商网站,你想用GA记录客流量、购买量信息,这时候W可以是一个引流的广告网站,这个引流的广告网站说我也要你们网站的购买量数据,这样我就知道我这个广告产生了多大作用,所以你也得发一份给我>^<)

然后每次搬砖工都得含辛茹苦地把工具包代码搬到html里,再在页面上同样的位置放置发送代码,搬砖工也很累哒!orz
然后搬砖工打开了GTM,他眼前一亮。
金色传说!
GTM就可以帮你管理这部分 要发给其他网站的 代码。

目前我琢磨到的使用方式如下:

  • GTM工具js还是要放html里的,GTM的跟踪工具window.dataLayer 也是要的。
  • 比如说n个网站都要“购买”数据,那你就只需要建立一个购买的触发器。
  • 然后根据需要建立变量,(自定义变量->变量类型为数据层变量,这样就可以从datalayer发来的对象里自动找到这个变量了)
    在这里插入图片描述
  • 建立完变量之后就建立 事件 (也就是代码),我使用的方式主要是发送 像素事件。
    我根据购买的number,去发送像素,从图里可以看得出,可以在事件里获得发来的数据并处理的。
    这段代码会被插入到你现在页面的html里,所以直接只写一段< img />也是可以的。
    在这里插入图片描述

最后就这样可以使用GTM了。
这样的跟踪方式其实是转手了一道,比如我购买了一个东西,触发了触发器,然后触发器再触发事件去处理传来的数据,向我的网站发送像素,接下来收到像素的我的网站,再发送跟踪请求,到正确的网站W。
也因此GTM被称为第三方代码管理器。

但是好处是你不用把这些代码写在自己的项目里了,比如同一个购买行为要发到5个网站,以前你要写好多代码,黏贴好多东西进你的项目,现在,你只需要发送一段datalayer(“purchase”)去触发购买触发器,然后把代码都放在GTM里,触发器自行触发,发出请求。


理论部分

参考内容来自于官方文档:
https://developers.google.com/analytics/devguides/collection/analyticsjs
简易版:
https://support.google.com/analytics/answer/1008080
在这里插入图片描述

首先申请个id,然后再有一个公网ip地址作为媒体资源的申请地址。

接下来在代码里进行操作。

1、将ga的创建代码在项目开始的时候运行一下,如下图。

可以写一个analysis()函数,在项目启动的时候运行,以下代码会自动将全局函数ga 注册到window上,之后就可以打印一下window.ga看看。
在这里插入图片描述

<!-- Google Analytics -->
<script>
/**
 * Creates a temporary global ga object and loads analytics.js.
 * Parameters o, a, and m are all used internally. They could have been
 * declared using 'var', instead they are declared as parameters to save
 * 4 bytes ('var ').
 *
 * @param {Window}        i The global context object.
 * @param {HTMLDocument}  s The DOM document object.
 * @param {string}        o Must be 'script'.
 * @param {string}        g Protocol relative URL of the analytics.js script.
 * @param {string}        r Global name of analytics object. Defaults to 'ga'.
 * @param {HTMLElement}   a Async script tag.
 * @param {HTMLElement}   m First script tag in document.
 */
(function(i, s, o, g, r, a, m){
  i['GoogleAnalyticsObject'] = r; // Acts as a pointer to support renaming.

  // Creates an initial ga() function.
  // The queued commands will be executed once analytics.js loads.
  i[r] = i[r] || function() {
    (i[r].q = i[r].q || []).push(arguments)
  },

  // Sets the time (as an integer) this tag was executed.
  // Used for timing hits.
  i[r].l = 1 * new Date();

  // Insert the script tag asynchronously.
  // Inserts above current tag to prevent blocking in addition to using the
  // async attribute.
  a = s.createElement(o),
  m = s.getElementsByTagName(o)[0];
  a.async = 1;
  a.src = g;
  m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');

// Creates a default tracker with automatic cookie domain configuration.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sends a pageview hit from the tracker just created.
ga('send', 'pageview');
</script>
<!-- End Google Analytics -->

2、ga函数是什么

emmm打印出来是这样的,8是很懂,总之好像是要使用analysis.js文件?
然后并不是一个简单的函数,使用它主要是先创建链接(create),然后再发送事件ga(‘send’, ‘pageview’);
在这里插入图片描述
啊。lucky。官网里详细说明了这个函数是什么。
命令队列的命令以及对应参数参考:https://developers.google.com/analytics/devguides/collection/analyticsjs/command-queue-reference
在这里插入图片描述
所以使用的时候先创建,创建完之后会根据下载下来的analysis.js文件重写window.ga函数。
window.ga函数对象拥有几个常用属性:
以及可以使用readyCallback,也就是回调函数,会在js文件下载完,所有ga命令队列中的历史命令执行完之后 执行,参数是跟踪器实例数组
1、函数:getAll()、getName
跟踪器实例的一些方法:
1、get(“name”) 获取数据。 之前看到的tracker.name这种方法打印不出跟踪器的name。默认跟踪器的name为t0。
2、set(“page”,“xxx”) 设置数据

3、发送数据

使用send命令。
可以参考这个博客使用GTM:https://blog.youkuaiyun.com/william_n/article/details/104001559
(Gtag官网参考地址:
https://developers.google.com/gtagjs
https://developers.google.com/analytics/devguides/collection/gtagjs

如何在站点查看发送数据
在这里插入图片描述

1、网页浏览数据追踪:
ga(‘send’, ‘pageview’);一般一个页面一个,我也好奇为啥不写上第三个参数,把pathname写上去。
监听路由跳转函数,在每一次跳转的时候就发送一次

history.listen(data=>{
	window.ga && window.ga('send', 'pageview');
})

官网上这么写的,应该是会自动捕获路由。

// 尝试用这个代码打印出自己的追踪其内部属性数据看看
    window.ga && window.ga.getAll().forEach(trackers=>{
      console.log(trackers.get("name"),trackers.get("page"),trackers.get("location"),trackers.get("title"))
    })

在这里插入图片描述

原因2是。好像说单页面应用不用。
因为我们在发送之前,需要更新跟踪器,也就是使用(“set”,“page”,xxx)这样去更新当前的浏览网页,对于单页面应用来说有一些交互行为是可能会引起错误(?)
来源:https://zhuanlan.zhihu.com/p/83747967
来源2(官网):https://developers.google.com/analytics/devguides/collection/analyticsjs/single-page-applications?hl=zh-cn

在这里插入图片描述

实践

申请账号和媒体资源:

首先(大受震撼.jpg)现在我们创建的GA资源一般都是GA4媒体资源,有两个特点:
1、媒体资源ID前面没有了UA开头的号码。
2、GA4项目没有数据视图。(应该是全部合并成使用标签创建?没有太看得懂)

在这里插入图片描述

目前这篇文章还是针对Universal Analytics版本(GA4之前的版本)做学习。因为大部分网站现在其实还是用的GA3,而且GA4太新了我找不到学习资料哈哈哈,(4版本的控制页面也和3完全不同),反正Universal Analytics版本后面也可以升级GA4,而GA4无法降级回来,所以就创建3版本的啦。

如果你发现你创建的媒体资源号前面没有UA开头,可以考虑重新创建账号。
参考:https://zhuanlan.zhihu.com/p/317729827

我买了个9块一年的域名,用这个申请了账号。

设置跟踪代码,衡量网页浏览

看这里看这里,官网的教程

首先尝试配置网页浏览事件。
我图方便,直接用umi建网页,因此编译html也隐藏起来了(弊端哈哈哈),嗯,所以我没有像教程里说的放在< script>里面,我直接放在一个运行时启动的函数里,像这样
在这里插入图片描述
接下来再加上一个路由监听,每一次监听都发送一次网页浏览事件。
在这里插入图片描述
然后你再转回到analysis的页面,就会看到这样监听出来了。
呜哇!啪啪啪鼓掌。
在这里插入图片描述
点开侧边 实时->内容,可能会看到这样的页面,出于各种考虑,可能会需要记录用户进入网站的方式等等。

在这里插入图片描述
你可能会疑惑,什么是来源、媒介 怎么设置它们?
来源/媒介 是google已经设置好的相匹配的一对数据,比如 google / organic、facebook.com / referral、pixnet.net / referral、(direct) / (none)
更详细的可以看看这篇文章(真的很详细): https://www.webguide.nat.gov.tw/News_Content.aspx?n=531&s=2935
(里面的管道分组在简体里好像是被翻译成 渠道分组)

既然是 “网页浏览量”,那可能就会有一个问题:

怎么定义一次浏览、一个用户多次浏览的话如何保证数据精准

GA的会话设定,必看
这三篇都读一下,感觉有帮助。
在这里插入图片描述

ga把一次会话理解为一个容器,其中包含了用户在网站上执行的操作。默认来说一次会话是30分钟时限,其中还有广告跳转、午夜重新更新的规则。

关于userID的官方解读1
userID与cookie解读2
如何保证精确性,其实GA会在浏览器cookie里留下一个针对浏览器的唯一id,它的默认时长有2年,但是换浏览器会失效、比如手机和网页同时看会记为两个用户,因此我们网站可以使用自己设置的userID,之后发送给ga网站分析时,它会认为我们设置同一个userID就是同一个用户。

window.ga && window.ga('set', 'userId', userId);
其他参考

防止浏览量虚高,对第三方referral做调整,比如对于电商,用户下单后跳转到第三方支付网站支付,如果支付不成功,有跳转回来,这种情况会造成新的会话开启,导致会话虚高,因此需要对GA做设置,使得GA遇到上述情况的时候不会开启新的会话,(也就是过滤)设置的地方在Property下的Referral Exclusion List。
https://www.ichdata.com/install-ga-tracking-code.html

设置跟踪事件

网页浏览只能看到路由的维度,而要细分到页面上的某个操作,必须以“事件”(event)为维度跟踪。
ga使用send方式发送跟踪时间,gtag使用另一种方式。

但是共通都是有几个衡量量词:

名称使用值(ga / gtag)说明
< action>eventAction / event_category将在 Google Analytics(分析)事件报告中显示为事件操作的值。(互动名称)
< category>eventCategory / event_category事件类别,通常是用户与之互动的对象(例如 ‘Video’)
< label>eventLabel / event_label事件标签,事件的描述等

在这里插入图片描述

设置完后可以在这里看到
在这里插入图片描述

插件使用

基本使用网页浏览+事件记录就可以满足大部分需求了,如果产品有更精细的维度需求,再慢慢看新的教程吧。
插件的话使用一个ecommerce 电子商务插件。
也就是电子商务跟踪。
1、先在报告里打开跟踪。(管理,数据视图,电子商务设置,打开即可。)
可以设置事件标签漏斗。
在这里插入图片描述

2、在代码中加入插件 ga(‘require’, ‘ecommerce’);
3、如何使用。

  • https://developers.google.com/analytics/devguides/collection/analyticsjs/ecommerce

添加完交易数据和商品数据后别忘了send。

在这里插入图片描述

转化指标

比如设置一个目标,接下来给某个事件设置价值。
在这里插入图片描述

GTM和GA

学着学着看到一个新概念,叫做:GTM
全称google tag manage。
但是我不清楚明明已经有了send event方式,为什么还要引入一个新概念去操作页面上的事件呢?
然后我找了一些资料:
https://www.jianshu.com/p/e66457eff06b

在这里插入图片描述
GTM是跟踪代码管理器,和我们用的GA不一样。。
虽然最后它们的事件点击数据追踪都是会汇集到我们的GA报告里的,不过资料里都说使用GTM去跟踪埋点更易于后期维护,和不妨碍现有的代码逻辑。

创建一个跟踪代码管理器。
使用指南: https://developers.google.com/tag-manager/quickstart

<think>好的,用户需要C++实现迷宫最少步数的问题。首先,我应该回忆一下这类问题的常见解法。通常,这类问题可以用广度优先搜索(BFS)算法来解决,因为BFS适合寻找无权图中的最短路径。迷宫中的每个格子可以看作是图中的一个节点,相邻的空地格子之间有一条边。BFS会逐层扩展,一旦找到终点,就能保证路径是最短的。 接下来,我需要考虑输入格式。根据用户提供的引用内容,输入第一行是R和C,代表迷宫的行数和列数。接下来的R行每行有C个字符,'.'表示空地,'#'表示障碍物。起点是左上角(0,0),终点是右下角(R-1, C-1),且这两个位置都是空地。 然后是具体实现步骤。首先需要读取输入,将迷宫存储为一个二维数组。然后使用队列来进行BFS。还需要一个二维数组来记录到达每个位置所需的步数,或者标记是否已访问。每一步需要检查上下左右四个方向,如果相邻格子是空地且未被访问过,则将其加入队列,并更新步数。 需要注意边界条件,比如当R或C为1时的情况。同时,队列的初始状态是起点,步数为1(因为包括起点和终点)。每次从队列中取出一个位置,检查是否是终点,如果是则返回步数。否则,遍历四个方向,符合条件的加入队列,并标记已访问。 可能还需要处理队列为空的情况,即无法到达终点,但根据题目描述,题目可能保证有解,但用户的问题中没有说明是否需要处理无解的情况,所以可能返回-1或者0表示无法到达。但根据引用中的描述,可能题目保证了起点和终点都是空地,但中间是否有路径不确定,所以代中可能需要处理这种情况。 然后,代结构大致如下:定义方向数组,处理输入,初始化队列和访问数组,进行BFS循环。每一步处理当前节点的四个邻居,判断是否合法(在迷宫范围内,未被访问,且是空地)。 测试样例方面,用户可能没有提供,但需要确保代正确处理示例输入,例如引用中的情况。例如,一个3x3的迷宫,中间有障碍物,路径可能需要绕行,此时步数是否正确。 另外,关于步数的计算,起点和终点都要算进去,所以初始步数是1,每次移动到新位置时步数是当前步数加1。例如,起点是0,0,步数为1,下一个位置步数就是2,直到终点。 现在考虑代的正确性。比如,访问数组要防止重复访问,否则可能导致无限循环。同时,队列中存储的位置需要携带步数信息,或者在进入队列时更新步数数组。常见的做法是用一个二维数组dist来记录每个位置的步数,初始化为-1或0,起点设置为1,之后每次扩展时设置对应位置的步数。 可能的错误点包括方向数组的定义是否正确,边界条件是否正确处理,访问数组的初始化和更新是否正确,以及队列的FIFO顺序是否正确维护。 最后,编写代时要符合C++的语法,使用STL的队列结构,可能使用pair表示坐标,或者结构体。例如,使用queue<pair<int, int>>来存储坐标,同时有一个二维数组dist来记录步数。方向数组可以定义为四个方向的dx和dy数组。 总结步骤: 1. 读取R和C,然后读取迷宫地图。 2. 初始化队列,将起点(0,0)加入队列,并标记dist[0][0] = 1。 3. BFS循环,直到队列为空或找到终点。 4. 每次取出队首元素,检查是否是终点,是则返回步数。 5. 否则,遍历四个方向,检查是否合法,若合法则设置步数并加入队列。 6. 如果队列空且未找到终点,返回-1(如果题目允许的话)。 现在需要将这些逻辑转化为C++代。同时,确保正确处理输入,比如迷宫的行输入可能有换行符需要注意,或者使用cin读取时自动跳过空格,但需要确保每个字符都被正确读取。 可能的代实现如下: #include <iostream> #include <queue> using namespace std; int main() { int R, C; cin >> R >> C; vector<vector<char>> maze(R, vector<char>(C)); for (int i = 0; i < R; ++i) { for (int j = 0; j < C; ++j) { cin >> maze[i][j]; } } queue<pair<int, int>> q; vector<vector<int>> dist(R, vector<int>(C, -1)); q.push({0, 0}); dist[0][0] = 1; int dx[] = {-1, 1, 0, 0}; int dy[] = {0, 0, -1, 1}; while (!q.empty()) { auto [x, y] = q.front(); q.pop(); if (x == R-1 && y == C-1) { cout << dist[x][y] << endl; return 0; } for (int i = 0; i < 4; ++i) { int nx = x + dx[i]; int ny = y + dy[i]; if (nx >= 0 && nx < R && ny >=0 && ny < C && maze[nx][ny] == '.' && dist[nx][ny] == -1) { dist[nx][ny] = dist[x][y] + 1; q.push({nx, ny}); } } } // 如果无法到达 cout << -1 << endl; return 0; } 这样应该可以处理大部分情况。需要确保在C++11及以上编译,因为使用了结构化绑定(auto [x,y])。如果编译器不支持,可以改用传统的.first和.second访问。 另外,测试一个例子: 比如输入: 3 5 ..... .###. ..... 应该输出步数,比如从(0,0)(2,4)的最短路径可能需要绕行,步数可能为 3+5+...需要具体看路径。或者另一个例子: 输入: 3 3 ... .## ... 输出步数可能为5(0,0)(0,1)(0,2)(1,2)(2,2),步数为5? 不过需要实际验证。但代逻辑正确的话,BFS会找到最短路径。 最后,用户可能需要这样的代,所以给出上述实现,并解释关键点。</think>以下是用C++实现迷宫最短路径的BFS算法代及解析: ```cpp #include <iostream> #include <queue> #include <vector> using namespace std; int main() { int R, C; cin >> R >> C; vector<vector<char>> maze(R, vector<char>(C)); // 读取迷宫数据 for (int i = 0; i < R; ++i) for (int j = 0; j < C; ++j) cin >> maze[i][j]; // BFS队列和距离记录数组 queue<pair<int, int>> q; vector<vector<int>> dist(R, vector<int>(C, -1)); const int dx[] = {-1, 1, 0, 0}; // 上下左右方向 const int dy[] = {0, 0, -1, 1}; // 初始化起点 q.push({0, 0}); dist[0][0] = 1; // 包含起点和终点[^2] while (!q.empty()) { auto [x, y] = q.front(); q.pop(); // 到达终点立即返回结果 if (x == R-1 && y == C-1) { cout << dist[x][y] << endl; return 0; } // 遍历四个方向 for (int i = 0; i < 4; ++i) { int nx = x + dx[i]; int ny = y + dy[i]; // 有效性检查:边界、可通行、未访问 if (nx >= 0 && nx < R && ny >= 0 && ny < C && maze[nx][ny] == '.' && dist[nx][ny] == -1) { dist[nx][ny] = dist[x][y] + 1; q.push({nx, ny}); } } } // 无法到达终点的情况 cout << -1 << endl; return 0; } ``` ### 关键点说明 1. **BFS算法**:采用广度优先搜索逐层扩展,确保找到的路径是最短路径 2. **队列结构**:使用`queue<pair<int, int>>`存储待处理的坐标 3. **距离记录**:通过二维数组`dist`同时实现访问标记和步数记录 4. **方向控制**:通过预定义的dx/dy数组实现四个方向的遍历 5. **边界处理**:检查坐标是否在合法范围内(0 ≤ x < R,0 ≤ y < C) 6. **复杂度**:时间复杂度$O(R×C)$,空间复杂度$O(R×C)$
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值