Extract MCQs

Extract MCQs from the Popular Site https://www.sanfoundry.com

// ==UserScript==
// @name         Extract MCQs
// @namespace    themrsami
// @version      2.5
// @description  Extract MCQs from the Popular Site https://www.sanfoundry.com
// @author       You
// @match        *://*.sanfoundry.com/*
// @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);

    function extractMCQs() {
// 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>
        // Initialize score counters
        let correctCount = 0;
        let incorrectCount = 0;
        
        // Initialize timer
        let timer = 0;
        let timerElement = document.getElementById('timer');
        
        // Start timer
        setInterval(function() {
            timer++;
            let minutes = Math.floor(timer / 60);
            let seconds = timer % 60;
            timerElement.textContent = (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
        }, 1000);
        
        window.checkAnswer = function(questionIndex, optionIndex) {
            let options = document.getElementById('options-' + questionIndex).children;
            let answerElement = document.getElementById('answer-' + questionIndex);
            let answer = answerElement.textContent.split(': ')[1].trim().toLowerCase();
            for (let i = 0; i < options.length; i++) {
                // Disable all options
                options[i].classList.add('cursor-not-allowed', 'opacity-50');
                options[i].setAttribute('onclick', '');
        
                if (i === optionIndex) {
                    options[i].classList.add('selected');
                    if (answer.includes(options[i].textContent.trim()[0].toLowerCase())) {
                        options[i].classList.remove('bg-blue-100', 'hover:bg-blue-200');
                        options[i].classList.add('bg-green-500');
                        correctCount++;
                    } else {
                        options[i].classList.remove('bg-blue-100', 'hover:bg-blue-200');
                        options[i].classList.add('bg-red-500');
                        incorrectCount++;
                    }
                }
            }
        
            // Update score counters
            document.getElementById('correct-count').textContent = correctCount;
            document.getElementById('incorrect-count').textContent = incorrectCount;
        };
    </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', extractMCQs);
})();