SkillRack Math Captcha Solver

Solves Math Captcha on the SkillRack website using Tesseract.js.

目前為 2024-11-21 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         SkillRack Math Captcha Solver
// @namespace    http://tampermonkey.net/
// @version      0.4
// @description  Solves Math Captcha on the SkillRack website using Tesseract.js.
// @author       Bit-Blazer
// @license      GNU GPLv3
// @match        https://www.skillrack.com/faces/candidate/codeprogram.xhtml
// @match        https://www.skillrack.com/faces/candidate/tutorprogram.xhtml
// @icon         https://envs.sh/GiG.png
// @require      https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js
// @grant        none
// ==/UserScript==

(function () {
  "use strict";

  // Define the IDs of the captcha image, input field, and proceed button
  const CAPTCHA_INPUT = "capval";
  const PROCEED_BTN = "proceedbtn";

  /**
   * Inverts the colors of the Captcha Image for better OCR results.
   * This is useful for enhancing the text recognition capability of Tesseract.js.
   * @param {HTMLImageElement} image - The image to be inverted.
   * @returns {string} - Base64 encoded data URL of the inverted image.
   */
  function invertColors(image) {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    canvas.width = image.width;
    canvas.height = image.height;
    ctx.drawImage(image, 0, 0);
    ctx.globalCompositeOperation = "difference"; // Invert colors
    ctx.fillStyle = "white"; // Set background to white
    ctx.fillRect(0, 0, canvas.width, canvas.height); // Fill the canvas
    return canvas.toDataURL(); // Return the inverted image as a data URL
  }

  /**
   * Extracts the username from the span element.
   * This function looks for the username pattern in the badge label.
   * @returns {string} - The extracted username or an empty string if not found.
   */
  function getUsername() {
    const usernameElement = document.querySelector(".ui-badge-label"); // Select the username element
    const match = usernameElement
      ? usernameElement.textContent.match(/(\d{12}@\w{3})/)
      : null; // Match the username pattern
    return match ? match[0] : ""; // Return the matched username or empty string
  }

  /**
   * Solves the captcha by extracting numbers and performing the calculation.
   * @param {string} text - The OCR result from the captcha image.
   * @param {string} username - The username to be removed from the OCR text.
   * @returns {number|null} - The result of the addition or null if not found.
   */
  function solveCaptcha(text, username) {
    // Remove the username from the OCR text and trim whitespace
    const cleanedText = text.replace(new RegExp(username, "gi"), "").trim();
    // Match the addition pattern in the cleaned text
    const match = cleanedText.match(/(\d+)\s*\+\s*(\d+)/);
    // Return the sum of the two numbers if a match is found
    return match ? parseInt(match[1], 10) + parseInt(match[2], 10) : null;
  }

  /**
   * Handles the captcha-solving process.
   * This function orchestrates the overall captcha solving by coordinating image processing and user interactions.
   */
  async function handleCaptcha() {
    // Get the captcha elements from the DOM
    const captchaImage = document.querySelector("img[src*='data:image']");
    const captchaInput = document.getElementById(CAPTCHA_INPUT);
    const proceedBtn = document.getElementById(PROCEED_BTN);

    // Log an error and exit if any elements are not found
    if (!captchaImage || !captchaInput || !proceedBtn) {
      console.log("Captcha or input elements not found.");
      return; // Stop execution
    }

    // Get the username from the UI
    const username = getUsername();
    // Invert the colors of the captcha image for better OCR processing
    const invertedImg = invertColors(captchaImage);

    try {
      // Process the inverted image using Tesseract.js for OCR
      const {
        data: { text },
      } = await Tesseract.recognize(invertedImg, "eng", {
        whitelist:
          "1234567890+=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@ ", // Allowed characters
        psm: 6, // Page segmentation mode
      });

      // Solve the Captcha using the OCR text and username
      const result = solveCaptcha(text, username);
      // Notify if the captcha could not be solved
      if (result === null) {
        console.log("Unable to solve Captcha. Please try again.");
        return; // Stop execution
      }
      // Fill the captcha input with the calculated result
      captchaInput.value = result;
      // Click the submit button to proceed
      proceedBtn.click();
    } catch (error) {
      // Log any errors encountered during the OCR process
      console.error("Error processing captcha:", error);
      alert(
        "An error occurred while processing the captcha. Please try again."
      ); // Notify user
    }
  }

  // Wait for the window to fully load before handling the captcha
  window.addEventListener("load", handleCaptcha);
})();