油猴子从入门到喵喵喵喵(实例:9/9 完结)

示例七:加入统计代码

建议先阅读:【老鼠讲故事系列 004】油猴子加入统计代码

第一步:判断用户设置

如果用户拒绝追踪,那就不要插入统计代码。

if (!navigator.doNotTrack) {
    // 这里是后续的代码
}

如果 navigator.doNotTrack 结果为 1,则禁止跟踪。0 为允许,未设置为 null

第二步:插入一个框架

这是因为我们可以对框架进行更好的操作,比如修改网址和标题,而不会影响到用户对页面浏览的体验。而这些修改可以让统计携带回更多有效的数据。

这并不是打算做什么坏事,是因为我们要跟踪的是脚本的使用情况,而脚本相关的一些数据并不能够通过普通的统计来获得。

框架中的页面最好是一个十分分简单,并且访问速度非常快的页面,比较好的选择就是一些网站的 404 页面,我使用了,提供统计服务的网站的某个页面。这样如果这个页面都无法访问,那么统计代码大概率也无法生效。

const href = 'https://c.statcounter.com/' + window.location.hostname + '/';
const iframe = document.createElement('iframe');
iframe.src = href;
iframe.style = 'display: none !important; width: 0; height: 0;';
document.body.appendChild(iframe);

就是很简单的在页面中追加一个元素,在加入之前对元素的一些属性进行必要的设置。这里我将当前页面的域名部分附加在了这个页面网址之后,我们可以以类似的方式附加一些有效信息。当然要确保最后这个网址所获得的页面符合我们的预期。

记得设置这个框架隐藏起来,不要显示。

第三步:对这个页面进行修改

首先我们要把上一个页面放入脚本的匹配( @match )之中。然后我们的脚本要可以在框架下运行。

如果发现当前页面的网址和我们预设的这个页面相匹配。就去修改这个页面的标题,让它携带更多信息,比如我让他携带了脚本管理器的名称、版本、当前脚本的版本号等。

if (/^https:\/\/c\.statcounter\.com\//i.test(window.location.href)) {
        // 在标题中放入脚本相关信息
        document.title = GM_info.scriptHandler+
            '-' + GM_info.version +
            '-' + GM_info.script.version
}

第四步:加入统计代码

这里要注意,不能直接通过修改 html 代码来插入,因为可能导致脚本没有正确的运行,所以还是要像上面那样,通过追加元素的方式进行插入,但在这之前可以先简单清空一下 body 元素中的内容。下面代码中项目编号和加密的识别码,我都用变量替代了。

document.body.innerHTML = '';
const scriptA = document.createElement('script');
scriptA.type = 'text/javascript';
scriptA.innerHTML =
  `var sc_project=` + sc_project + `;
  var sc_invisible=1;
  var sc_security="` + sc_security + `";
  var sc_https=1;
  var sc_remove_link=1;
`;
document.body.append(scriptA);

第五步:优化兼容性

一般统计代码在脚本无法正确运行的时候,会采取备用方式,就是插入一张图片。这里我们准备好这张图片,当上面的代码没有能够正确注入时,就插入这一张图片。同样的,代码中项目编号和加密的识别码,我都用变量替代了。

scriptB.type = 'text/javascript';
scriptB.src = 'https://www.statcounter.com/counter/counter.js';
document.body.append(scriptB);
scriptB.onerror = () => {
  const img = document.createElement('img');
  img.src =
    'https://c.statcounter.com/' +
    sc_project +
    '/0/' +
    sc_security +
    '/1/#' +
    Number(new Date());
  img.style = 'display: none';
  document.body.append(img);

第六步:降低干扰

这个干扰是双方向的,一方面在页面打开时就插入统计代码,虽然影响本身是很小的,但终归会让页面打开的速度稍微慢一丢丢。如果等页面彻底打开之后,再去加入统计代码,这样对用户的影响会更小。

同时如果用户还没有等这个页面彻底打开,就将页面关闭了,那么对这个页面进行统计也没有什么必要。所以我将插入框架的时间进行了一个延迟。

第七步:控制次数

但是我只是希望了解用户使用的脚本管理器和一些版本号的情况。就没有必要用户访问,每一个页面都进行统计。所以我设置了每天只统计一次。但这一点需要脚本管理器提供数据存储的接口才能够实现。

首先我获取当前的时间,然后除以一天的好秒数,将结果取整数作为一个标记。

然后查看脚本存取的数据里的标记和这个标记是否相同,如果相同那么意味着今天已经做过统计了,就无需再插入统计代码。如果不同,那么插入统计代码,同时更新储存的这个标记为当前标记。


以上便是在脚本中放入统计代码的思路分析,都不复杂,但是这些细节我也确实思考了好久,尽自己的可能去降低对用户的影响。

下面放出相对完整的代码:

// 如果用户拒绝追踪,则不添加统计代码
if (!navigator.doNotTrack) {
  // 如果是预定页面,则进行改造
  if (/^https:\/\/c\.statcounter\.com\//i.test(window.location.href)) {
    // 在标题中放入脚本相关信息
    document.title = GM_info
      ? GM_info.scriptHandler.replace(/monkey/i, '') +
        '-' +
        GM_info.version +
        '-' +
        GM_info.script.version
      : navigator.userAgent + '-' + scriptVersion;
    // 插入统计代码
    document.body.innerHTML = '';
    const scriptA = document.createElement('script');
    scriptA.type = 'text/javascript';
    scriptA.innerHTML =
      `var sc_project=` + sc_project + `;
      var sc_invisible=1;
      var sc_security="` + sc_security + `";
      var sc_https=1;
      var sc_remove_link=1;
    `;
    document.body.append(scriptA);
    const scriptB = document.createElement('script');
    scriptB.type = 'text/javascript';
    scriptB.src = 'https://www.statcounter.com/counter/counter.js';
    document.body.append(scriptB);
    scriptB.onerror = () => {
      const img = document.createElement('img');
      img.src =
        'https://c.statcounter.com/' +
        sc_project +
        '/0/' +
        sc_security +
        '/1/#' +
        Number(new Date());
      img.style = 'display: none';
      document.body.append(img);
    };
  } else {
    // 非预定页面则插入统计代码
    setTimeout(() => {
      const todayMark = Math.floor(+new Date() / 864e5); // 获取今日时间标记
      const recordMark = GM_getValue('timeMark', 0); // 获取记录中时间标记
      if (todayMark !== recordMark) {
        // 时间标记不同则插入统计代码
        const href =
          'https://c.statcounter.com/' + window.location.hostname + '/';
        const iframe = document.createElement('iframe');
        iframe.src = href;
        iframe.style = 'display: none !important; width: 0; height: 0;';
        document.body.appendChild(iframe);
        GM_setValue('timeMark', todayMark); // 将新的时间标记存入记录
      }
    }, delay);
  }
}