开源一个掘金自动签到的油猴脚本

引言

作为一名掘金的忠实用户,我每天打开网站的第一件事就是签到。最近在写小册《油猴脚本实战指南》的收尾章节---------如何将油猴脚本打包成原生谷歌插件 时,想着既然都提到提到谷歌插件开发了,于是顺手把 Chrome 插件的快速入门教程整理到小册里。

就是因为这几天持续的写作,居然连续忘了好几次掘金签到,难受!作为脚本开发者,这事儿不能忍,必须写一个掘金自动签到脚本干它!

脚本效果与使用方式

要使用这个脚本,必须先通过谷歌商店,下载油猴扩展插件。

如果你无法翻墙下载,可以加我,shc1139874527,群里有学习资料和油猴插件下载地址。

然后,就可以通过脚本地址安装插件并使用。

脚本使用非常简单,当你打开任意网页且掘金没有签到时,它就会自动帮你签到。如下图,当我打开百度页面时,自动打开掘金后台标签,签到完成后,后台标签关闭,首页进行了提示。

实现原理

技术栈

脚本的技术栈很简单,就是将一段签到脚本(javascript代码)通过油猴注入到网页中执行逻辑。

油猴 是一个谷歌扩展程序,你可以在Chrome应用商店中,搜索 "篡改猴"进行安装。

用户可以将自己编写的任何javascript脚本放在油猴中执行,从而实现网页加强的功能。此外,油猴还提供了一些API,实现了突破浏览器限制的JS能力,比如跨域请求无视CSP限制、后台打开标签等。

如果你对脚本开发感兴趣,不妨看看《油猴脚本实战指南》这本小册,目前7折,可冲。

脚本原理

脚本的原理其实非常简单,当用户打开任意网站后,脚本会利用油猴提供的 GM_openInTab API 打开掘金的签到页面:

js 复制代码
const targetPage = "https://juejin.cn/user/center/signin"; // 掘金签到页面地址
const bgTab = GM_openInTab(targetPage); 

在掘金签到页,脚本会通过获取签到按钮的Dom元素文本内容,判断用户是否签到。如果用户没有签到,脚本则模拟用户点击签到按钮。

js 复制代码
const signBtn = document.querySelector(".code-calender button.btn"); // 查找签到按钮
if (signBtn) {
  if (signBtn.innerText.includes("立即签到")) {
    signBtn.click(); // 模拟点击签到按钮
  }
}

完成签到后,脚本会自动关闭该标签页,并通过 GM_setValue 储存签到状态。这样,下一次用户访问其他网页时,脚本会先判断是否已经签过到,避免重复触发,提高效率。

完整代码

下面是脚本的完整代码,大家可以直接复制到油猴的脚本新建页面中使用。

js 复制代码
// ==UserScript==
// @name         掘金自动签到助手
// @namespace    http://tampermonkey.net/
// @version      0.0.1
// @description  掘金自动签到助手,后台打开标签页版本
// @author       石小石Orz
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_getTab
// @grant        GM_getTabs
// @grant        GM_saveTab
// @grant        GM_addElement
// @grant        unsafeWindow
// @grant        GM_openInTab
// @run-at       document-body
// @noframes
// ==/UserScript==

(async function () {
  "use strict";

  const targetPage = "https://juejin.cn/user/center/signin"; // 掘金签到页面地址
  const currentDate = new Date().toLocaleDateString(); // 获取当前日期(本地格式)
  const storedDate = GM_getValue("signTime", ""); // 读取上次签到的日期(默认空字符串)

  // 如果已经签到(存储的日期和今天一样),终止脚本执行
  if (storedDate === currentDate) return;

  // 显示签到成功提示框
  function showSuccessMessage(text = "掘金自动签到成功", duration = 3000) {
    const el = GM_addElement(document.body, "div", {
      textContent: text,
      style: `
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            background-color: #DAF7E1;
            color: #0C9B4A;
            padding: 10px 16px;
            font-size: 14px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
            z-index: 99999;
            opacity: 0;
            transition: opacity 0.3s ease, transform 0.3s ease;
          `,
    });

    // 动画效果:渐显+下移
    requestAnimationFrame(() => {
      el.style.opacity = "1";
      el.style.transform = "translateX(-50%) translateY(10px)";
    });

    // 指定时间后自动移除提示框
    setTimeout(() => {
      el.style.opacity = "0";
      el.style.transform = "translateX(-50%) translateY(0)";
      setTimeout(() => el.remove(), 300);
    }, duration);
  }

  //   尝试执行签到操作(仅在签到页使用)
  const trySignIn = (close) => {
    unsafeWindow.addEventListener("load", () => {
      setTimeout(() => {
        const signBtn = document.querySelector(".code-calender button.btn"); // 查找签到按钮
        if (signBtn) {
          if (signBtn.innerText.includes("立即签到")) {
            signBtn.click(); // 模拟点击签到按钮
          }
          // 无论是否签到成功,都保存当前日期作为签到日期
          GM_setValue("signTime", currentDate);
          close && window.close();
        }
      }, 1000);
    });
  };

  // 获取当前标签页对象与所有已知标签页
  const [tab, tabs] = await Promise.all([GM.getTab(), GM.getTabs()]);

  // 判断是否已有"主页面"存在(主页面用于协调多个标签页避免重复签到)
  const hasMainPage = Object.values(tabs).some((t) => t?.isMainPage);

  // 如果没有主页面
  if (!hasMainPage) {
    if (location.href.startsWith(targetPage)) {
      // 当前页面就是签到页,直接尝试签到
      trySignIn();
    } else {
      // 当前不是签到页,将本标签页设为主页面,并在后台打开签到页面
      tab.isMainPage = true;
      await GM.saveTab(tab);
      const bgTab = GM_openInTab(targetPage); // 打开后台签到页面
      bgTab.onclose = () => {
        showSuccessMessage(); // 签到页关闭后显示提示
      };
    }
  } else {
    // 如果已有主页面,仅在签到页执行签到逻辑
    if (location.href.startsWith(targetPage)) {
      trySignIn(!tab?.isMainPage); // 主页面不关闭,其他页面签到完关闭
    } else {
      // 非签到页,重复打开一个签到页面进行操作
      const bgTab = GM_openInTab(targetPage);
      bgTab.onclose = () => {
        showSuccessMessage(); // 签到页关闭后显示提示
      };
    }
  }
})();

上述代码中,使用了一些GM_setValueGM_getTabGM_addElementGM_openInTab等一些油猴的API能力,其余代码和普通前端代码是没有任何差异的。

这些API小册中有详细介绍,你也可以参考官方API文档学习。

总结

这篇文章给大家带来了一个非常实用的油猴脚本------掘金自动签到,有需求的同学还不快用起来!JYM,快成为矿石大亨!

油猴脚本开发对前端同学来说非常容易入门,感兴趣的同学可以去学习哇!

相关推荐
辻戋12 小时前
从零实现React Scheduler调度器
前端·react.js·前端框架
徐同保12 小时前
使用yarn@4.6.0装包,项目是react+vite搭建的,项目无法启动,报错:
前端·react.js·前端框架
Qrun13 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp13 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.14 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl16 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫18 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友18 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理20 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻20 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js