Auto Clicker for Example Website

Automates clicking on certain buttons on example.com

  1. // v1.4
  2.  
  3. const puppeteer = require('puppeteer');
  4.  
  5. (async () => {
  6. const DIR = {
  7. email: 'YOUR EMAIL', // replace YOUR EMAIL with your email for auto login (keep everything else the same)
  8. password: 'YOUR PASSWORD', // replace YOUR PASSWORD with your password for auto login
  9.  
  10. login_url: 'https://app.educationperfect.com/app/login',
  11.  
  12. // log-in page elements
  13. username_css: '#loginId',
  14. password_css: '#password',
  15.  
  16. // home page elements
  17. home_css: 'div.view-segment-dashboard',
  18.  
  19. // task-starter page elements
  20. baseList_css: 'div.baseLanguage',
  21. targetList_css: 'div.targetLanguage',
  22. start_button_css: 'button#start-button-main',
  23.  
  24. // task page elements
  25. modal_question_css: 'td#question-field',
  26. modal_correct_answer_css: 'td#correct-answer-field',
  27. modal_user_answered_css: 'td#users-answer-field',
  28. modal_css: 'div[uib-modal-window=modal-window]',
  29. modal_backdrop_css: 'div[uib-modal-backdrop=modal-backdrop]',
  30.  
  31. question_css: '#question-text',
  32. answer_box_css: 'input#answer-text',
  33.  
  34. exit_button_css: 'button.exit-button',
  35. exit_continue_button_css: 'button.continue-button',
  36.  
  37. continue_button_css: 'button#continue-button',
  38. }
  39.  
  40. // launch browser
  41. puppeteer.launch({
  42. headless: false,
  43. defaultViewport: null,
  44. handleSIGINT: false
  45. })
  46. .then(async browser => {
  47. const page = (await browser.pages())[0];
  48.  
  49. // Open EP page and log in
  50. console.log('Opening EP page...');
  51. await page.goto(DIR.login_url);
  52. console.log('Waiting for login page to load...');
  53. await page.waitForSelector(DIR.username_css);
  54.  
  55. // THIS FILLS IN YOUR DETAILS TO LOG IN AUTOMATICALLY
  56. console.log('Filling in login details...');
  57. await page.type(DIR.username_css, DIR.email);
  58. await page.type(DIR.password_css, DIR.password);
  59. await page.keyboard.press('Enter');
  60.  
  61. console.log('Waiting for home page to load...');
  62. await page.waitForSelector(DIR.home_css, { timeout: 0 });
  63. console.log('EP Home page loaded; Logged in.');
  64.  
  65.  
  66. // ===== Auto-answer code starts here ===== //
  67. let TOGGLE = false;
  68. let ENTER = true;
  69. let fullDict = {};
  70. let cutDict = {};
  71.  
  72. // Basic answer-parsing
  73. function cleanString(string) {
  74. return String(string)
  75. .replace(/\([^)]*\)/g, "").trim()
  76. .split(";")[0].trim()
  77. .split(",")[0].trim()
  78. .split("|")[0].trim();
  79. }
  80.  
  81. // Get words from the main task page
  82. async function wordList(selector) {
  83. return await page.$$eval(selector, els => {
  84. let words = [];
  85. els.forEach(i => words.push(i.textContent));
  86. return words;
  87. });
  88. }
  89.  
  90. // Refreshes the world lists on the main task page to enhance our vocabulary
  91. async function refreshWords() {
  92. const l1 = await wordList(DIR.baseList_css);
  93. const l2 = await wordList(DIR.targetList_css);
  94. for (let i = 0; i < l1.length; i++) {
  95. fullDict[l2[i]] = cleanString(l1[i]);
  96. fullDict[l1[i]] = cleanString(l2[i]);
  97. cutDict[cleanString(l2[i])] = cleanString(l1[i]);
  98. cutDict[cleanString(l1[i])] = cleanString(l2[i]);
  99. }
  100. console.log('Word Lists Refreshed.');
  101. await alert('Word Lists Refreshed.');
  102. }
  103.  
  104.  
  105. // extracts what (EP detected as) the user typed, from the fancy multicolored display
  106. // appended to logs for debugging/self-learning purposes
  107. async function getModalAnswered() {
  108. return await page.$$eval('td#users-answer-field > *', el => {
  109. let answered = '';
  110. el.forEach(i => {
  111. if (i.textContent !== null && i.style.color !== 'rgba(0, 0, 0, 0.25)') answered = answered + i.textContent;
  112. })
  113. return answered;
  114. });
  115. }
  116.  
  117. // Learn from the mistakes :)
  118. async function correctAnswer(question, answer) {
  119. // wait until modal content is fully loaded
  120. await page.waitForFunction((css) => {
  121. return document.querySelector(css).textContent !== "blau";
  122. }, {}, DIR.modal_question_css);
  123.  
  124. // extract modal contents (for debugging and correcting answers)
  125. let modalQuestion = await page.$eval(DIR.modal_question_css, el => el.textContent);
  126. let modalAnswer = await page.$eval(DIR.modal_correct_answer_css, el => el.textContent);
  127. let modalCutAnswer = cleanString(modalAnswer);
  128. let modalAnswered = await getModalAnswered();
  129.  
  130. // dismisses the modal (bypasses the required cooldown)
  131. await page.$eval(DIR.continue_button_css, el => el.disabled = false);
  132. await page.click(DIR.continue_button_css);
  133.  
  134. // update/correct answer dictionary
  135. fullDict[question] = modalCutAnswer;
  136.  
  137. // logging for debugging if needed
  138. let log = "===== Details after Incorrect Answer: =====\n"
  139. log = log + `Detected Question: \n => ${question}\n`;
  140. log = log + `Inputted Answer: \n => ${answer}\n\n`;
  141. log = log + `Modal Question: \n => ${modalQuestion}\n`;
  142. log = log + `Modal Full Answer: \n => ${modalAnswer}\n`;
  143. log = log + `Modal Cut Answer: \n => ${modalCutAnswer}\n`;
  144. log = log + `Modal Detected Answered: \n => ${modalAnswered}\n\n\n`;
  145.  
  146. console.log(log);
  147. }
  148.  
  149. // deletes all existing modals and backdrops. Used to force-speed things up
  150. async function deleteModals() {
  151. await page.$$eval(DIR.modal_css, el => {
  152. el.forEach(i => i.remove())
  153. });
  154. await page.$$eval(DIR.modal_backdrop_css, el => {
  155. el.forEach(i => i.remove())
  156. });
  157. }
  158.  
  159. // very advanced logic (ofc) used to find matching answer
  160. function findAnswer(question) {
  161. let answer = fullDict[question];
  162. if (answer) return answer;
  163. answer = fullDict[question.replace(",", ";")];
  164. if (answer) return answer;
  165. answer = cutDict[cleanString(question)];
  166. if (answer) return answer;
  167. console.log(`No answer found for ${question}`);
  168. return generateRandomString(8, 10);
  169. }
  170.  
  171. // i love creating functions so here's one for the random string instead of just returning idk answer
  172. // -joshatticus
  173. function generateRandomString(minLength, maxLength) {
  174. const length = Math.floor(Math.random() * (maxLength - minLength + 1)) + minLength;
  175. const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  176. let result = '';
  177. for (let i = 0; i < length; i++) {
  178. result += characters.charAt(Math.floor(Math.random() * characters.length));
  179. }
  180. return result;
  181. }
  182.  
  183. // main function that continually answers questions until completion modal pops up or hotkey pressed again
  184. async function answerLoop() {
  185. if (TOGGLE) throw Error("Tried to initiate answerLoop while it is already running");
  186.  
  187. TOGGLE = true;
  188. console.log("answerLoop entered.");
  189.  
  190. while (TOGGLE) {
  191. let question = await page.$eval(DIR.question_css, el => el.textContent);
  192. let answer = findAnswer(question);
  193.  
  194. await page.click(DIR.answer_box_css, { clickCount: 3 });
  195. await page.keyboard.sendCharacter(answer);
  196. ENTER && page.keyboard.press('Enter');
  197.  
  198. // special case: modal pops up
  199. if (await page.$(DIR.modal_css)) {
  200. // incorrect answer and modal pops up; initiate answer-correction procedure
  201. if (await page.$(DIR.modal_question_css) !== null) {
  202. await correctAnswer(question, answer);
  203. await deleteModals();
  204. // list complete; clicks button to exit
  205. } else if (await page.$(DIR.exit_button_css)) {
  206. await page.click(DIR.exit_button_css);
  207. break;
  208. } else if (await page.$(DIR.exit_continue_button_css)) {
  209. await page.click(DIR.exit_continue_button_css);
  210. break;
  211. } else {
  212. // no idea what the modal is for so let's just pretend it doesn't exist
  213. await deleteModals();
  214. }
  215. }
  216. }
  217.  
  218. await deleteModals();
  219. TOGGLE = false;
  220. console.log('answerLoop Exited.');
  221. }
  222.  
  223. // takes care of answerLoop toggling logic
  224. async function toggleLoop() {
  225. if (TOGGLE) {
  226. TOGGLE = false;
  227. console.log("Stopping answerLoop.");
  228. } else {
  229. console.log("Starting answerLoop.");
  230. answerLoop().catch(e => {
  231. console.error(e);
  232. TOGGLE = false
  233. });
  234. }
  235. }
  236.  
  237. async function toggleAuto() {
  238. if (ENTER) {
  239. ENTER = false;
  240. console.log("Switched to semi-auto mode.");
  241. await alert("Switched to semi-auto mode.");
  242. } else {
  243. ENTER = true;
  244. console.log("Switched to auto mode.");
  245. await alert("Switched to auto mode.");
  246. }
  247. }
  248.  
  249. async function alert(msg) {
  250. await page.evaluate(m => window.alert(m), msg);
  251. }
  252.  
  253. // Expose API functions to the page (for hotkey event listeners to call)
  254. await page.exposeFunction('refresh', refreshWords);
  255. await page.exposeFunction('startAnswer', toggleLoop);
  256. await page.exposeFunction('toggleMode', toggleAuto);
  257.  
  258. // Add event listeners for hotkeys ON the page
  259. await page.evaluate(() => {
  260. document.addEventListener("keyup", async (event) => {
  261. let key = event.key.toLowerCase();
  262. if (key !== 'alt') {
  263. if ((event.altKey && key === "r") || (key === "®")) {
  264. await window.refresh();
  265. } else if ((event.altKey && key === "s") || (key === "ß")) {
  266. await window.startAnswer();
  267. } else if ((event.altKey && key === "a") || (key === "å")) {
  268. await window.toggleMode();
  269. }
  270. }
  271. });
  272. });
  273. console.log('Education Perfected V2 fully Loaded.');
  274. });
  275. })();
  276.  
  277. // ==UserScript==
  278. // @name Auto Clicker for Example Website
  279. // @namespace http://example.com/
  280. // @version 0.1
  281. // @description Automates clicking on certain buttons on example.com
  282. // @author Your Name
  283. // @match http://example.com/*
  284. // @license MIT
  285. // @grant none
  286. // ==/UserScript==
  287.  
  288. // Your script code goes here

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址