// ==UserScript==
// @name hyw自动答题助手
// @namespace http://tampermonkey.net/
// @version 0.3.6
// @description hyw自动答题脚本
// @author 小马
// @license MIT
// @match https://hyw.shixizhi.huawei.com/*
// @grant GM_addStyle
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @run-at document-end
// @require https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js
// ==/UserScript==
(function () {
'use strict';
let questionBank = [];
// 添加面板样式
GM_addStyle(`
.answer-panel {
position: fixed;
top: 20px;
right: 20px;
background: white;
padding: 15px;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 2147483647; /* 最大z-index值 */
min-width: 200px;
font-family: Arial, sans-serif;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
.answer-panel h3 {
margin: 0 0 10px 0;
padding: 0;
font-size: 16px;
color: #333;
}
.answer-panel select,
.answer-panel input,
.answer-panel button {
margin: 5px 0;
padding: 5px;
width: 100%;
box-sizing: border-box;
}
.answer-panel button {
background: #007bff;
color: white;
border: none;
border-radius: 3px;
padding: 8px;
margin: 5px 0;
cursor: pointer;
}
.answer-panel button:hover {
background: #0056b3;
}
#status {
margin-top: 10px;
color: #666;
font-size: 14px;
word-break: break-all;
}
/* 确保面板始终可见 */
.answer-panel * {
display: block;
visibility: visible !important;
opacity: 1 !important;
}
`);
// 创建控制面板
function createPanel() {
try {
// 先检查是否已存在面板
const existingPanel = document.querySelector('.answer-panel');
if (existingPanel) {
existingPanel.remove();
}
const panel = document.createElement('div');
panel.className = 'answer-panel';
panel.innerHTML = `
<div>
<h3>自动答题助手</h3>
<select id="examType">
<option value="security">保密考试</option>
<option value="functional">职能考试</option>
</select>
<input type="file" id="fileInput" accept=".xlsx,.xls">
<button id="startBtn">开始答题</button>
<button id="stopBtn">停止答题</button>
<div id="status">等待上传题库...</div>
</div>
`;
// 确保面板被添加到 body 的最后
document.body.appendChild(panel);
// 添加拖拽相关变量
let isDragging = false;
let currentX;
let currentY;
let initialX;
let initialY;
let xOffset = 0;
let yOffset = 0;
// 拖拽开始
function dragStart(e) {
// 如果点击的是select、input或button元素,不启动拖拽
if (e.target.tagName.toLowerCase() === 'select' ||
e.target.tagName.toLowerCase() === 'input' ||
e.target.tagName.toLowerCase() === 'button') {
return;
}
if (e.type === "mousedown") {
initialX = e.clientX - xOffset;
initialY = e.clientY - yOffset;
} else if (e.type === "touchstart") {
initialX = e.touches[0].clientX - xOffset;
initialY = e.touches[0].clientY - yOffset;
}
if (e.target === panel || panel.contains(e.target)) {
isDragging = true;
}
}
// 拖拽过程
function drag(e) {
if (isDragging) {
e.preventDefault();
if (e.type === "mousemove") {
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
} else if (e.type === "touchmove") {
currentX = e.touches[0].clientX - initialX;
currentY = e.touches[0].clientY - initialY;
}
xOffset = currentX;
yOffset = currentY;
setTranslate(currentX, currentY, panel);
}
}
// 设置面板位置
function setTranslate(xPos, yPos, el) {
el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`;
}
// 拖拽结束
function dragEnd() {
initialX = currentX;
initialY = currentY;
isDragging = false;
}
// 添加拖拽事件监听
panel.addEventListener('mousedown', dragStart, false);
document.addEventListener('mousemove', drag, false);
document.addEventListener('mouseup', dragEnd, false);
panel.addEventListener('touchstart', dragStart, false);
document.addEventListener('touchmove', drag, false);
document.addEventListener('touchend', dragEnd, false);
// 阻止select的mousedown事件冒泡
document.getElementById('examType').addEventListener('mousedown', (e) => {
e.stopPropagation();
});
// 原有的事件绑定
document.getElementById('fileInput').addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) processExcel(file);
});
document.getElementById('startBtn').addEventListener('click', startAutoAnswer);
document.getElementById('stopBtn').addEventListener('click', stopAutoAnswer);
} catch (error) {
console.error('创建控制面板失败:', error);
// 可以尝试使用更简单的备用面板
try {
const simplePanel = document.createElement('div');
simplePanel.className = 'answer-panel';
simplePanel.innerHTML = `
<div>
<h3>自动答题助手(简易版)</h3>
<input type="file" id="fileInput" accept=".xlsx,.xls">
<button id="startBtn">开始答题</button>
<button id="stopBtn">停止答题</button>
<div id="status">等待上传题库...</div>
</div>
`;
document.body.appendChild(simplePanel);
} catch (backupError) {
console.error('创建备用面板也失败:', backupError);
}
}
}
// 更新状态显示
function updateStatus(message) {
document.getElementById('status').textContent = message;
}
let isRunning = false;
// 停止自动答题
function stopAutoAnswer() {
isRunning = false;
updateStatus('已停止答题');
}
// 开始自动答题
async function startAutoAnswer() {
if (questionBank.length === 0) {
updateStatus('请先上传题库!');
return;
}
isRunning = true;
updateStatus('开始自动答题...');
while (isRunning) {
try {
const questionInfo = getCurrentQuestionInfo();
if (!questionInfo.question) {
updateStatus('未检测到题目,可能已完成答题');
isRunning = false;
break;
}
console.log('当前题目:', questionInfo.question);
const answerInfo = findAnswer(questionInfo.question);
if (answerInfo) {
const selected = selectAnswer(answerInfo, questionInfo.isMultipleChoice);
if (selected) {
updateStatus(`已答题: ${questionInfo.question.substring(0, 20)}...`);
// 减少答题后的等待时间为500ms
await new Promise(resolve => setTimeout(resolve, 200));
if (!clickNext(true)) {
updateStatus('无法找到下一题按钮,停止答题');
isRunning = false;
break;
}
} else {
updateStatus('答案选择失败');
if (!clickNext(false)) break;
}
} else {
updateStatus('未找到匹配答案');
if (!clickNext(false)) break;
}
// 减少题目之间的等待时间为500ms
await new Promise(resolve => setTimeout(resolve, 200));
} catch (error) {
console.error('答题过程出错:', error);
updateStatus('答题过程出错,已停止');
isRunning = false;
break;
}
}
}
// 处理Excel文件上传
async function handleFileUpload(e) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = function (e) {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
questionBank = XLSX.utils.sheet_to_json(firstSheet);
document.getElementById('status').innerText = `已加载 ${questionBank.length} 道题目`;
};
reader.readAsArrayBuffer(file);
}
// 处理Excel数据结构
function processExcel(file) {
const reader = new FileReader();
reader.onload = function (e) {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
const jsonData = XLSX.utils.sheet_to_json(firstSheet);
// 获取当前选择的考试类型
const examType = document.getElementById('examType').value;
// 根据不同的考试类型处理数据
if (examType === 'security') {
// 保密考试题库格式
questionBank = jsonData.map(row => ({
sequence: row['序号'],
type: row['试题类别'],
questionId: row['试题类型'],
question: row['试题题目'],
options: row['选项'],
answer: row['正确答案']
}));
} else if (examType === 'functional') {
// 职能考试题格式
questionBank = jsonData.map(row => ({
sequence: row['题库'],
type: row['题型'],
questionId: '',
question: row['题目'],
options: `${row['选项A']}\n${row['选项B']}\n${row['选项C']}\n${row['选项D']}\n${row['选项E'] || ''}\n${row['选项F'] || ''}\n${row['选项G'] || ''}\n${row['选项H'] || ''}`.trim(),
answer: row['正确答案']
}));
}
updateStatus(`已导入 ${questionBank.length} 道题目`);
};
reader.readAsArrayBuffer(file);
}
// 查找答案
function findAnswer(currentQuestion) {
try {
// 获取当前页面的所有选项文本
const currentOptions = Array.from(document.querySelectorAll('.option-list-item'))
.map(option => option.textContent.trim());
console.log('当前页面选项:', currentOptions);
// 在题库中查找匹配的题目
const matchedQuestions = questionBank.filter(item =>
item.question.includes(currentQuestion) ||
currentQuestion.includes(item.question)
);
console.log('匹配到的题目:', matchedQuestions);
if (matchedQuestions.length === 0) {
return null;
}
// 如果只有一个匹配项,直接返回
if (matchedQuestions.length === 1) {
return {
answer: matchedQuestions[0].answer,
type: matchedQuestions[0].type,
options: matchedQuestions[0].options
};
}
// 如果有多个匹配项,通过比对选项找到最匹配的题目
let bestMatch = null;
let highestMatchScore = 0;
for (const question of matchedQuestions) {
// 将题库中的选项按分隔符分割并清理
const bankOptions = question.options.split(/[\n^]/)
.map(opt => opt.trim())
.filter(opt => opt)
.map(opt => opt.replace(/^[A-Z]\s*[..、]\s*/, '').trim()); // 移除选项标记
// 计算选项匹配分数
let matchScore = 0;
let matchedOptionsCount = 0;
// 对每个当前页面的选项进行匹配度计算
for (const currentOpt of currentOptions) {
const cleanCurrentOpt = currentOpt.replace(/^[A-Z]\s*[..、]\s*/, '').trim();
// 在题库选项中寻找最佳匹配
const bestOptionMatch = bankOptions.find(bankOpt => {
// 完全匹配得3分
if (bankOpt === cleanCurrentOpt) {
return true;
}
// 包含关系得2分
if (bankOpt.includes(cleanCurrentOpt) || cleanCurrentOpt.includes(bankOpt)) {
return true;
}
// 部分词语匹配得1分
const bankWords = bankOpt.split(/\s+/);
const currentWords = cleanCurrentOpt.split(/\s+/);
return bankWords.some(word => currentWords.includes(word));
});
if (bestOptionMatch) {
matchedOptionsCount++;
if (bestOptionMatch === cleanCurrentOpt) {
matchScore += 3;
} else if (bestOptionMatch.includes(cleanCurrentOpt) || cleanCurrentOpt.includes(bestOptionMatch)) {
matchScore += 2;
} else {
matchScore += 1;
}
}
}
// 计算最终匹配分数(考虑匹配的选项数量和匹配质量)
const finalScore = matchScore * (matchedOptionsCount / currentOptions.length);
// 更新最佳匹配
if (finalScore > highestMatchScore) {
highestMatchScore = finalScore;
bestMatch = question;
}
}
// 如果找到了足够好的匹配(设置一个阈值)
if (bestMatch && highestMatchScore >= currentOptions.length * 1.5) { // 阈值可以调整
return {
answer: bestMatch.answer,
type: bestMatch.type,
options: bestMatch.options
};
}
// 如果没有找到足够好的匹配,返回null
return null;
} catch (error) {
console.error('查找答案时出错:', error);
return null;
}
}
// 获取当前题目信息
function getCurrentQuestionInfo() {
try {
// 修改选择器以匹配实际DOM结构
const questionElement = document.querySelector('.main-title .content');
if (!questionElement) {
console.log('未找到题目元素');
return { question: '', isMultipleChoice: false };
}
const question = questionElement.textContent.trim();
// 判断是否为多选题 - 检查题类型标签
const typeElement = document.querySelector('.type-name');
const isMultipleChoice = typeElement && typeElement.textContent.includes('多选题');
return { question, isMultipleChoice };
} catch (error) {
console.error('获取题目信息出错:', error);
return { question: '', isMultipleChoice: false };
}
}
// 选择答案
function selectAnswer(answerInfo, isMultipleChoice) {
try {
if (!answerInfo) return false;
const options = document.querySelectorAll('.option-list-item');
let selected = false;
console.log('answerInfo:', answerInfo);
// 使用 ^ 作为分隔符分割选项
const allOptions = answerInfo.options.split('^').map(opt => opt.trim());
console.log('allOptions', allOptions);
if (isMultipleChoice) {
// 多选题处理:答案可能是多个字母组合(如"ABC")
const correctAnswers = answerInfo.answer.split('').map(letter => {
return allOptions.find(opt =>
opt.startsWith(letter + '.') || // 中文点号
opt.startsWith(letter + '.') || // 英文点号
opt.startsWith(letter + '、') || // 顿号
opt.startsWith(letter + ' 、') || // 空格+顿号
opt.match(new RegExp(`^${letter}\\s*[..、]`)) // 通用格式
);
}).filter(Boolean); // 移除未找到的选项
console.log('correctAnswers:', correctAnswers);
// 遍历页面上的选项
options.forEach((option) => {
const optionText = option.textContent.trim();
// 检查当前选项是否是正确答案之一
const isCorrectOption = correctAnswers.some(correctAnswer => {
const correctContent = correctAnswer.replace(/^[A-Z]\s*[..、]\s*/, '').trim();
return optionText.includes(correctContent) || correctContent.includes(optionText);
});
const input = option.querySelector('input[type="checkbox"]');
if (input && isCorrectOption && !input.checked) {
input.click();
selected = true;
}
});
} else {
// 单选题处理(保持原有逻辑)
const correctAnswerContent = allOptions.find(opt =>
opt.startsWith(answerInfo.answer + '.') ||
opt.startsWith(answerInfo.answer + '.') ||
opt.startsWith(answerInfo.answer + '、') ||
opt.startsWith(answerInfo.answer + ' 、') ||
opt.match(new RegExp(`^${answerInfo.answer}\\s*[..、]`))
);
if (!correctAnswerContent) return false;
options.forEach((option) => {
const optionText = option.textContent.trim();
const correctContent = correctAnswerContent.replace(/^[A-Z]\s*[..、]\s*/, '').trim();
if (optionText.includes(correctContent) || correctContent.includes(optionText)) {
const input = option.querySelector('input[type="radio"]');
if (input && !input.checked) {
input.click();
selected = true;
}
}
});
}
return selected;
} catch (error) {
console.error('选择答案出错:', error);
return false;
}
}
// 点击下一题
function clickNext(answered) {
try {
// 获取下一题按钮
const nextButton = Array.from(document.querySelectorAll('.subject-btns .subject-btn'))
.find(button => button.textContent.trim() === '下一题');
// 点击下一题按钮
if (nextButton) {
nextButton.click();
return true;
}
return false;
} catch (error) {
console.error('点击下一题按钮出错:', error);
return false;
}
}
// 修改初始化部分
function init() {
// 等待页面完全加载
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => setTimeout(createPanel, 1000));
} else {
setTimeout(createPanel, 1000);
}
}
// 使用 window.onload 确保所有资源都加载完成
window.addEventListener('load', () => {
setTimeout(init, 1000);
});
})();