Extract MCQs

Extract MCQs from the webpage

目前為 2024-02-26 提交的版本,檢視 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Extract MCQs
// @namespace    themrsami
// @version      2.0
// @description  Extract MCQs from the webpage
// @author       You
// @match        http://*/*
// @match        https://*/*
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Add some CSS for the button
    GM_addStyle(`
        #extract-mcqs-button {
            position: fixed;
            bottom: 20px;
            right: 20px;
            padding: 10px 20px;
            font-size: 16px;
            color: white;
            background-color: #007BFF;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            z-index: 9999;
        }
        #extract-mcqs-button:hover {
            background-color: #0056b3;
        }
    `);

    // Create the button
    let button = document.createElement('button');
    button.id = 'extract-mcqs-button';
    button.innerText = 'Extract MCQs';
    document.body.appendChild(button);

GM_registerMenuCommand('Extract MCQs', function() {
// Remove elements that destroy the structure
let elementsToRemove = [
    ...document.querySelectorAll('div[style="margin:30px 0px;"]'),
    ...document.querySelectorAll('div.sf-mobile-ads'),
    ...document.querySelectorAll('div.sf-desktop-ads'),
    ...document.querySelectorAll('span.collapseomatic')
];

for (let element of elementsToRemove) {
    if (element.parentNode) {
        element.parentNode.removeChild(element);
    }
}

let pTags = document.getElementsByTagName('p');
let results = [];

for (let i = 0; i < pTags.length; i++) {
    let imgHref = null;
    let aTag = pTags[i].getElementsByTagName('a')[0];
    if (aTag) {
        let imgTag = aTag.getElementsByTagName('img')[0];
        if (imgTag) {
            imgHref = imgTag.src || imgTag.getAttribute('data-src');
            aTag.parentNode.removeChild(aTag);
        }
    }

    let startsWithNumber = /^\d/.test(pTags[i].textContent);
    let nextSibling = pTags[i].nextElementSibling;
    if (startsWithNumber && nextSibling && nextSibling.tagName.toLowerCase() === 'div' && nextSibling.classList.contains('collapseomatic_content')) {
        let statementAndOptions = pTags[i].innerHTML.split('<br>');
        let statement = statementAndOptions.shift();
        let options = statementAndOptions.join('<br>').replace(/\n/g, '');
        let answerAndExplanation = nextSibling.innerHTML.split('<br>');
        let answer = answerAndExplanation.shift().replace(/\n/g, '');
        let explanation = answerAndExplanation.join('<br>').replace(/\n/g, '');
        results.push({
            statement: statement,
            imgHref: imgHref,
            options: options,
            answer: answer,
            explanation: explanation
        });
    }

    let nextDiv = pTags[i].nextElementSibling;
    if (nextDiv && nextDiv.tagName.toLowerCase() === 'div' && nextDiv.classList.contains('hk1_style-wrap5')) {
        let pre = nextDiv.getElementsByTagName('pre')[0];
        if (pre) {
            let nextP = nextDiv.nextElementSibling;
            if (nextP && nextP.tagName.toLowerCase() === 'p') {
                let nextDiv2 = nextP.nextElementSibling;
                if (nextDiv2 && nextDiv2.tagName.toLowerCase() === 'div' && nextDiv2.classList.contains('collapseomatic_content')) {
                    let statement = pTags[i].textContent;
                    let preContent = pre.textContent.replace(/\n/g, '');
                    let options = nextP.innerHTML.split('<br>').join('<br>').replace(/\n/g, '');
                    let answerAndExplanation = nextDiv2.innerHTML.split('<br>');
                    let answer = answerAndExplanation.shift().replace(/\n/g, '');
                    let explanation = answerAndExplanation.join('<br>').replace(/\n/g, '');
                    results.push({
                        statement: statement,
                        preContent: preContent,
                        options: options,
                        answer: answer,
                        explanation: explanation
                    });
                }
            }
        }

        let del1 = nextDiv.getElementsByClassName('del1')[0];
        if (del1) {
            let statement = pTags[i].textContent + ' ' + del1.textContent;
            let nextP = nextDiv.nextElementSibling;
            if (nextP && nextP.tagName.toLowerCase() === 'p') {
                let nextDiv2 = nextP.nextElementSibling;
                if (nextDiv2 && nextDiv2.tagName.toLowerCase() === 'div' && nextDiv2.classList.contains('collapseomatic_content')) {
                    let options = nextP.innerHTML.split('<br>').join('<br>').replace(/\n/g, '');
                    let answerAndExplanation = nextDiv2.innerHTML.split('<br>');
                    let answer = answerAndExplanation.shift().replace(/\n/g, '');
                    let explanation = answerAndExplanation.join('<br>').replace(/\n/g, '');
                    results.push({
                        statement: statement,
                        options: options,
                        answer: answer,
                        explanation: explanation
                    });
                }
            }
        }
    }
}

console.log(JSON.stringify(results, null, 2));


// ... Your existing code to extract the MCQs ...

// Now let's generate the HTML
let html = `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"="width=device-width, initial-scale=1.0">
    <title>Quiz</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        @tailwind base;
        @tailwind components;
        @tailwind utilities;

        .option:hover:not(.selected) {
          @apply bg-gray-300;
        }
        .correct {
          @apply bg-green-200;
        }
        .incorrect {
          @apply bg-red-200;
        }
        .selected {
          @apply bg-gray-400;
        }
        .option:hover {
          @apply scale-105;
        }
        .selected {
          @apply scale-110;
        }
        .option:focus {
          @apply ring-4 ring-blue-500 ring-offset-2 ring-offset-gray-100;
        }
    </style>
</head>
<body class="bg-gray-100 p-10">

    <div class="flex justify-between items-center mb-4 sticky top-0 bg-white z-50">
        <div>
            <p class="text-lg font-bold">Time: <span id="timer" class="text-blue-500">00:00</span></p>
        </div>
        <div>
            <p class="text-lg font-bold text-green-500">Correct: <span id="correct-count">0</span></p>
            <p class="text-lg font-bold text-red-500">Incorrect: <span id="incorrect-count">0</span></p>
        </div>
    </div>



    ${results.map((result, index) => `
    <div class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4 flex flex-col my-2">
        <div class="md:flex mb-6">
            <div class="md:w-1/2 px-3">
                <label class="block uppercase tracking-wide text-blue-900 text-lg font-bold mb-2" for="grid-first-name">
                    Q${index + 1}: ${result.statement.replace(/^\d+\.\s*/, '')}
                </label>
                ${result.preContent ? `<pre>${result.preContent}</pre>` : ''}
            </div>
            <div class="md:w-1/2 px-3">
                ${result.imgHref ? `<img src="${result.imgHref}" alt="Image" class="mb-4">` : ''}
            </div>
        </div>
        <div class="md:flex mb-6">
            <div class="md:w-full px-3">
                <div id="options-${index}" class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    ${result.options.split('<br>').map((option, optionIndex) => option.trim() !== "" ? `
                    <p class="option cursor-pointer py-2 px-4 rounded bg-blue-100 hover:bg-blue-200" onclick="checkAnswer(${index}, ${optionIndex})">${option}</p>
                    ` : '').join('')}
                </div>
                <button class="mt-3 text-white bg-blue-700 border-0 py-2 px-6 focus:outline-none hover:bg-blue-800 rounded text-lg" onclick="document.getElementById('answer-${index}').classList.toggle('hidden');document.getElementById('explanation-${index}').classList.toggle('hidden');">Show/Hide Answer</button>
                <p id="answer-${index}" class="hidden mt-3 text-grey-darker text-base bg-gray-200 p-4 rounded">${result.answer}</p>
                <p id="explanation-${index}" class="hidden mt-3 text-grey-darker text-base bg-gray-200 p-4 rounded">${result.explanation}</p>
            </div>
        </div>
    </div>
    `).join('')}
    <script src="script.js"></script>
</body>
</html>`;

// Download the file
let blob = new Blob([html], {type: "text/html;charset=utf-8"});
let link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "quiz.html";
link.click();});

    // Add an event listener to the button
    button.addEventListener('click', function() {
        // Execute the menu command
        GM_executeMenuCommand('Extract MCQs');
    });

})();