SkillRack Math Captcha Solver

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

目前为 2024-10-26 提交的版本。查看 最新版本

// ==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/codeprogramgroup.xhtml
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @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_IMAGE = "j_id_78";
    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 specified 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.getElementById(CAPTCHA_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) {
            alert("Captcha or input elements not found."); // Notify user
            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) {
                alert("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);
})();