Extract MCQs

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

  1. // ==UserScript==
  2. // @name Extract MCQs
  3. // @namespace themrsami
  4. // @version 2.5
  5. // @description Extract MCQs from the Popular Site https://www.sanfoundry.com
  6. // @author You
  7. // @match *://*.sanfoundry.com/*
  8. // @grant GM_registerMenuCommand
  9. // @grant GM_addStyle
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. // Add some CSS for the button
  18. GM_addStyle(`
  19. #extract-mcqs-button {
  20. position: fixed;
  21. bottom: 20px;
  22. right: 20px;
  23. padding: 10px 20px;
  24. font-size: 16px;
  25. color: white;
  26. background-color: #007BFF;
  27. border: none;
  28. border-radius: 5px;
  29. cursor: pointer;
  30. z-index: 9999;
  31. }
  32. #extract-mcqs-button:hover {
  33. background-color: #0056b3;
  34. }
  35. `);
  36.  
  37. // Create the button
  38. let button = document.createElement('button');
  39. button.id = 'extract-mcqs-button';
  40. button.innerText = 'Extract MCQs';
  41. document.body.appendChild(button);
  42.  
  43. function extractMCQs() {
  44. // Remove elements that destroy the structure
  45. let elementsToRemove = [
  46. ...document.querySelectorAll('div[style="margin:30px 0px;"]'),
  47. ...document.querySelectorAll('div.sf-mobile-ads'),
  48. ...document.querySelectorAll('div.sf-desktop-ads'),
  49. ...document.querySelectorAll('span.collapseomatic')
  50. ];
  51.  
  52. for (let element of elementsToRemove) {
  53. if (element.parentNode) {
  54. element.parentNode.removeChild(element);
  55. }
  56. }
  57.  
  58. let pTags = document.getElementsByTagName('p');
  59. let results = [];
  60.  
  61. for (let i = 0; i < pTags.length; i++) {
  62. let imgHref = null;
  63. let aTag = pTags[i].getElementsByTagName('a')[0];
  64. if (aTag) {
  65. let imgTag = aTag.getElementsByTagName('img')[0];
  66. if (imgTag) {
  67. imgHref = imgTag.src || imgTag.getAttribute('data-src');
  68. aTag.parentNode.removeChild(aTag);
  69. }
  70. }
  71.  
  72. let startsWithNumber = /^\d/.test(pTags[i].textContent);
  73. let nextSibling = pTags[i].nextElementSibling;
  74. if (startsWithNumber && nextSibling && nextSibling.tagName.toLowerCase() === 'div' && nextSibling.classList.contains('collapseomatic_content')) {
  75. let statementAndOptions = pTags[i].innerHTML.split('<br>');
  76. let statement = statementAndOptions.shift();
  77. let options = statementAndOptions.join('<br>').replace(/\n/g, '');
  78. let answerAndExplanation = nextSibling.innerHTML.split('<br>');
  79. let answer = answerAndExplanation.shift().replace(/\n/g, '');
  80. let explanation = answerAndExplanation.join('<br>').replace(/\n/g, '');
  81. results.push({
  82. statement: statement,
  83. imgHref: imgHref,
  84. options: options,
  85. answer: answer,
  86. explanation: explanation
  87. });
  88. }
  89.  
  90. let nextDiv = pTags[i].nextElementSibling;
  91. if (nextDiv && nextDiv.tagName.toLowerCase() === 'div' && nextDiv.classList.contains('hk1_style-wrap5')) {
  92. let pre = nextDiv.getElementsByTagName('pre')[0];
  93. if (pre) {
  94. let nextP = nextDiv.nextElementSibling;
  95. if (nextP && nextP.tagName.toLowerCase() === 'p') {
  96. let nextDiv2 = nextP.nextElementSibling;
  97. if (nextDiv2 && nextDiv2.tagName.toLowerCase() === 'div' && nextDiv2.classList.contains('collapseomatic_content')) {
  98. let statement = pTags[i].textContent;
  99. let preContent = pre.textContent.replace(/\n/g, '');
  100. let options = nextP.innerHTML.split('<br>').join('<br>').replace(/\n/g, '');
  101. let answerAndExplanation = nextDiv2.innerHTML.split('<br>');
  102. let answer = answerAndExplanation.shift().replace(/\n/g, '');
  103. let explanation = answerAndExplanation.join('<br>').replace(/\n/g, '');
  104. results.push({
  105. statement: statement,
  106. preContent: preContent,
  107. options: options,
  108. answer: answer,
  109. explanation: explanation
  110. });
  111. }
  112. }
  113. }
  114.  
  115. let del1 = nextDiv.getElementsByClassName('del1')[0];
  116. if (del1) {
  117. let statement = pTags[i].textContent + ' ' + del1.textContent;
  118. let nextP = nextDiv.nextElementSibling;
  119. if (nextP && nextP.tagName.toLowerCase() === 'p') {
  120. let nextDiv2 = nextP.nextElementSibling;
  121. if (nextDiv2 && nextDiv2.tagName.toLowerCase() === 'div' && nextDiv2.classList.contains('collapseomatic_content')) {
  122. let options = nextP.innerHTML.split('<br>').join('<br>').replace(/\n/g, '');
  123. let answerAndExplanation = nextDiv2.innerHTML.split('<br>');
  124. let answer = answerAndExplanation.shift().replace(/\n/g, '');
  125. let explanation = answerAndExplanation.join('<br>').replace(/\n/g, '');
  126. results.push({
  127. statement: statement,
  128. options: options,
  129. answer: answer,
  130. explanation: explanation
  131. });
  132. }
  133. }
  134. }
  135. }
  136. }
  137.  
  138. console.log(JSON.stringify(results, null, 2));
  139.  
  140.  
  141. // ... Your existing code to extract the MCQs ...
  142.  
  143. // Now let's generate the HTML
  144. let html = `
  145. <!DOCTYPE html>
  146. <html lang="en">
  147. <head>
  148. <meta charset="UTF-8">
  149. <meta name="viewport"="width=device-width, initial-scale=1.0">
  150. <title>Quiz</title>
  151. <script src="https://cdn.tailwindcss.com"></script>
  152. <style>
  153. @tailwind base;
  154. @tailwind components;
  155. @tailwind utilities;
  156.  
  157. .option:hover:not(.selected) {
  158. @apply bg-gray-300;
  159. }
  160. .correct {
  161. @apply bg-green-200;
  162. }
  163. .incorrect {
  164. @apply bg-red-200;
  165. }
  166. .selected {
  167. @apply bg-gray-400;
  168. }
  169. .option:hover {
  170. @apply scale-105;
  171. }
  172. .selected {
  173. @apply scale-110;
  174. }
  175. .option:focus {
  176. @apply ring-4 ring-blue-500 ring-offset-2 ring-offset-gray-100;
  177. }
  178. </style>
  179. </head>
  180. <body class="bg-gray-100 p-10">
  181.  
  182. <div class="flex justify-between items-center mb-4 sticky top-0 bg-white z-50">
  183. <div>
  184. <p class="text-lg font-bold">Time: <span id="timer" class="text-blue-500">00:00</span></p>
  185. </div>
  186. <div>
  187. <p class="text-lg font-bold text-green-500">Correct: <span id="correct-count">0</span></p>
  188. <p class="text-lg font-bold text-red-500">Incorrect: <span id="incorrect-count">0</span></p>
  189. </div>
  190. </div>
  191.  
  192.  
  193.  
  194. ${results.map((result, index) => `
  195. <div class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4 flex flex-col my-2">
  196. <div class="md:flex mb-6">
  197. <div class="md:w-1/2 px-3">
  198. <label class="block uppercase tracking-wide text-blue-900 text-lg font-bold mb-2" for="grid-first-name">
  199. Q${index + 1}: ${result.statement.replace(/^\d+\.\s*/, '')}
  200. </label>
  201. ${result.preContent ? `<pre>${result.preContent}</pre>` : ''}
  202. </div>
  203. <div class="md:w-1/2 px-3">
  204. ${result.imgHref ? `<img src="${result.imgHref}" alt="Image" class="mb-4">` : ''}
  205. </div>
  206. </div>
  207. <div class="md:flex mb-6">
  208. <div class="md:w-full px-3">
  209. <div id="options-${index}" class="grid grid-cols-1 md:grid-cols-2 gap-4">
  210. ${result.options.split('<br>').map((option, optionIndex) => option.trim() !== "" ? `
  211. <p class="option cursor-pointer py-2 px-4 rounded bg-blue-100 hover:bg-blue-200" onclick="checkAnswer(${index}, ${optionIndex})">${option}</p>
  212. ` : '').join('')}
  213. </div>
  214. <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>
  215. <p id="answer-${index}" class="hidden mt-3 text-grey-darker text-base bg-gray-200 p-4 rounded">${result.answer}</p>
  216. <p id="explanation-${index}" class="hidden mt-3 text-grey-darker text-base bg-gray-200 p-4 rounded">${result.explanation}</p>
  217. </div>
  218. </div>
  219. </div>
  220. `).join('')}
  221. <script>
  222. // Initialize score counters
  223. let correctCount = 0;
  224. let incorrectCount = 0;
  225. // Initialize timer
  226. let timer = 0;
  227. let timerElement = document.getElementById('timer');
  228. // Start timer
  229. setInterval(function() {
  230. timer++;
  231. let minutes = Math.floor(timer / 60);
  232. let seconds = timer % 60;
  233. timerElement.textContent = (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
  234. }, 1000);
  235. window.checkAnswer = function(questionIndex, optionIndex) {
  236. let options = document.getElementById('options-' + questionIndex).children;
  237. let answerElement = document.getElementById('answer-' + questionIndex);
  238. let answer = answerElement.textContent.split(': ')[1].trim().toLowerCase();
  239. for (let i = 0; i < options.length; i++) {
  240. // Disable all options
  241. options[i].classList.add('cursor-not-allowed', 'opacity-50');
  242. options[i].setAttribute('onclick', '');
  243. if (i === optionIndex) {
  244. options[i].classList.add('selected');
  245. if (answer.includes(options[i].textContent.trim()[0].toLowerCase())) {
  246. options[i].classList.remove('bg-blue-100', 'hover:bg-blue-200');
  247. options[i].classList.add('bg-green-500');
  248. correctCount++;
  249. } else {
  250. options[i].classList.remove('bg-blue-100', 'hover:bg-blue-200');
  251. options[i].classList.add('bg-red-500');
  252. incorrectCount++;
  253. }
  254. }
  255. }
  256. // Update score counters
  257. document.getElementById('correct-count').textContent = correctCount;
  258. document.getElementById('incorrect-count').textContent = incorrectCount;
  259. };
  260. </script>
  261. </body>
  262. </html>`;
  263.  
  264. // Download the file
  265. let blob = new Blob([html], {type: "text/html;charset=utf-8"});
  266. let link = document.createElement("a");
  267. link.href = URL.createObjectURL(blob);
  268. link.download = "quiz.html";
  269. link.click();}
  270.  
  271. // Add an event listener to the button
  272. button.addEventListener('click', extractMCQs);
  273. })();