自编油猴脚本

TamperMonkey 自编脚本(显然大部分都是 gpt 完成的)

两个挺方便的脚本。

SJTU-课表学分计算

基于 SJTU 学期课表的自动学分计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// ==UserScript==
// @name SJTU-课表学分计算
// @namespace http://tampermonkey.net/
// @version 0.7
// @description 拦截 XMLHttpRequest 请求,计算总学分并动态更新浮动框
// @author KyouyamaKazusa
// @match https://i.sjtu.edu.cn/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N2151&layout=default
// @grant none
// ==/UserScript==

(function () {
"use strict";

// 页面加载时初始化浮动框
initFloatingBox();

// 重写 XMLHttpRequest 的 open 方法以拦截请求
const originalOpen = XMLHttpRequest.prototype.open;

XMLHttpRequest.prototype.open = function (method, url, ...rest) {
// 检查是否是目标请求(课表请求的 URL)
if (url.includes("xskbcx_cxXsgrkb.html?gnmkdm=N2151")) {
this.addEventListener("readystatechange", function () {
if (this.readyState === 4 && this.status === 200) {
console.log("拦截到 XMLHttpRequest 请求:", url);

// 解析响应数据
const responseData = JSON.parse(this.responseText);
console.log("拦截到的课表数据:", responseData);

// 如果数据包含课表列表,计算总学分
if (responseData && responseData.kbList) {
const totalCredits = calculateTotalCredits(responseData.kbList);
console.log("总学分:", totalCredits);

// 更新浮动框的内容
updateFloatingBox(`总学分: ${totalCredits} 学分`);
} else {
console.log("未找到课表数据");
updateFloatingBox("未找到课表数据");
}
}
});
}

// 调用原始的 open 方法
return originalOpen.apply(this, [method, url, ...rest]);
};

// 初始化浮动框
function initFloatingBox() {
const container = document.createElement("div");
container.id = "floatingBox";
container.style.position = "fixed";
container.style.bottom = "20px";
container.style.right = "20px";
container.style.backgroundColor = "#f8f8f8";
container.style.border = "1px solid #ccc";
container.style.padding = "10px";
container.style.fontSize = "16px";
container.style.fontWeight = "bold";
container.style.boxShadow = "0px 0px 10px rgba(0, 0, 0, 0.1)";
container.style.zIndex = "9999";
container.style.borderRadius = "8px";
container.innerText = "总学分: 未查询"; // 初始状态显示未查询

// 将浮动框添加到页面
document.body.appendChild(container);
}

// 更新浮动框的内容
function updateFloatingBox(content) {
const container = document.getElementById("floatingBox");
if (container) {
container.innerText = content; // 更新内容
}
}

// 计算总学分的函数
function calculateTotalCredits(courseList) {
let totalCredits = 0;
const uniqueCourses = new Set(); // 使用 Set 去重

courseList.forEach((course) => {
const courseId = course.kch; // 假设课程编号字段为 kch
const credits = parseFloat(course.xf); // 假设学分字段为 xf

if (!uniqueCourses.has(courseId)) {
uniqueCourses.add(courseId);
totalCredits += credits;
}
});

return totalCredits;
}
})();

字幕库验证码自动填充

由于字幕库验证码较为简单(纯数字,无模糊与扭曲),可以直接本地识别,并自动填充

还有一个自动计算学分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// ==UserScript==
// @name 自动识别 XPath 验证码并填充
// @namespace http://tampermonkey.net/
// @version 1.1
// @description 使用 Tesseract.js 识别 XPath 验证码并自动填充
// @author KyouyamaKazusa
// @match https://srtku.com
// @grant none
// @require https://cdn.jsdelivr.net/npm/tesseract.js@4
// ==/UserScript==

(function () {
"use strict";

// 1️⃣ 获取验证码图片元素
function getCaptchaElement() {
let xpath = "/html/body/div/div[2]/table/tbody/tr[1]/td[3]/img"; // 你的验证码 XPath
let captchaImg = document.evaluate(
xpath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
return captchaImg;
}

// 2️⃣ 获取输入框元素
function getCaptchaInput() {
let xpath = "/html/body/div/div[2]/table/tbody/tr[1]/td[2]/input"; // 你的输入框 XPath
let inputField = document.evaluate(
xpath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
return inputField;
}

// 3️⃣ 获取登录按钮元素(如有)
function getLoginButton() {
return document.querySelector("#login-btn"); // 这里修改为你的登录按钮选择器
}

// 4️⃣ 将图片转换为 Canvas
function imageToCanvas(img) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
return canvas;
}

// 5️⃣ 识别验证码
async function recognizeCaptcha(canvas) {
let result = await Tesseract.recognize(canvas, "eng");
let captchaText = result.data.text.replace(/\s/g, ""); // 去掉空格
console.log("识别结果:", captchaText);
return captchaText;
}

// 6️⃣ 自动填充验证码并提交
async function fillCaptcha() {
let captchaImg = getCaptchaElement();
let inputField = getCaptchaInput();
let loginButton = getLoginButton();

if (!captchaImg || !inputField) {
console.warn("未找到验证码或输入框");
return;
}

// 监听图片加载,确保正确绘制
captchaImg.onload = async function () {
let canvas = imageToCanvas(captchaImg);
let captchaText = await recognizeCaptcha(canvas);

if (captchaText.length > 0) {
inputField.value = captchaText; // 自动填充验证码
console.log("填充验证码:", captchaText);

// 自动提交表单(如果需要)
if (loginButton) {
setTimeout(() => {
loginButton.click();
console.log("已提交表单");
}, 1000);
}
}
};

// 如果验证码已加载,直接处理
if (captchaImg.complete) {
captchaImg.onload();
}
}

setTimeout(fillCaptcha, 200); // 页面加载后延迟执行
})();

自编油猴脚本
https://0kitasan.github.io/2025/02/15/2025-02-15-自编油猴脚本/
作者
0kitasan
发布于
2025年2月15日
许可协议