Created
February 10, 2019 09:31
-
-
Save ericksli/85306bd0669c93c18ebe369d8307e88b to your computer and use it in GitHub Desktop.
Fill in the MTR late cert form usling puppeteer.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const puppeteer = require('puppeteer'); | |
const readline = require('readline'); | |
const sleep = require('util').promisify(setTimeout); | |
require('dotenv').config(); | |
const EVENT_SELECTOR = 'select#ddlEvent'; | |
const NAME_SELECTOR = 'input#username'; | |
const EMAIL_SELECTOR = 'input#email'; | |
const CAPTCHA_SELECTOR = 'input#captcha-form'; | |
const CAPTCHA_IMAGE_SELECTOR = 'img#captcha'; | |
const CAPTCHA_INVALID_SELECTOR = 'span#valid_captcha'; | |
const SUBMIT_FORM_SELECTOR = 'form#regform input[type="submit"]'; | |
let submitSuccess = false; | |
(async () => { | |
const browser = await puppeteer.launch({headless: process.env.HEADLESS === 'true'}); | |
const page = await browser.newPage(); | |
page.on('request', async request => { | |
console.log(request.url()); | |
if (submitSuccess) { | |
await onSubmitSuccess(browser); | |
} else if (request.url() === 'http://www.mtr.com.hk/eng/homepage/cust_index.html') { | |
await onNoLateCertProvide(browser) | |
} | |
}); | |
page.on('dialog', async dialog => { | |
if (dialog.message() === 'The form is submitted successfully') { | |
submitSuccess = true; | |
} | |
await dialog.accept(); | |
}); | |
await page.goto('https://tnsms1.mtr.com.hk/latecert/form_en.php'); | |
await agreeTerms(page); | |
const events = await getEvents(page); | |
await selectEvent(page, events[0].value); | |
await fillInContactInfo(page); | |
await changeCaptchaImage(page); | |
await extractCaptchaImage(page); | |
do { | |
const ans = await askQuestion("Type the CAPTCHA: "); | |
await fillInCaptcha(page, ans); | |
await submitForm(page); | |
await sleep(3000); | |
if (!submitSuccess) { | |
const captchaCorrect = await isCaptchaCorrect(page); | |
console.log('captchaCorrect: ' + captchaCorrect); | |
await changeCaptchaImage(page); | |
await extractCaptchaImage(page); | |
} | |
} while (!submitSuccess); | |
})(); | |
async function agreeTerms(page) { | |
await page.waitForSelector('#form_agree'); | |
await page.click('input[type="submit"][value="Agree and submit"]'); | |
} | |
async function getEvents(page) { | |
await page.waitForSelector(EVENT_SELECTOR); | |
return await page.evaluate((selector) => { | |
return Array.apply(null, document.querySelector(selector).options) | |
.map(item => { | |
return {text: item.text, value: item.value} | |
}); | |
}, EVENT_SELECTOR); | |
} | |
async function selectEvent(page, value) { | |
await page.select(EVENT_SELECTOR, value); | |
} | |
async function fillInContactInfo(page) { | |
await page.type(NAME_SELECTOR, 'Your Name'); | |
await page.type(EMAIL_SELECTOR, '[email protected]'); | |
} | |
async function fillInCaptcha(page, captchaText) { | |
await page.evaluate((selector) => document.querySelector(selector).value = "", CAPTCHA_SELECTOR); | |
await page.type(CAPTCHA_SELECTOR, captchaText); | |
} | |
async function extractCaptchaImage(page) { | |
const captcha = await page.$(CAPTCHA_IMAGE_SELECTOR); | |
await captcha.screenshot({ | |
path: 'captcha.png', | |
omitBackground: true, | |
}); | |
} | |
async function changeCaptchaImage(page) { | |
await page.click('a[href="javascript:changeCaptcha()"]'); | |
} | |
async function submitForm(page) { | |
await page.click(SUBMIT_FORM_SELECTOR); | |
} | |
async function isCaptchaCorrect(page) { | |
try { | |
await page.waitForNavigation({waitUntil: "networkidle0", timeout: 1500}); | |
} catch (e) { | |
} | |
try { | |
return await page.$eval(CAPTCHA_INVALID_SELECTOR, (elem) => window.getComputedStyle(elem).getPropertyValue('display') === 'none'); | |
} catch (e) { | |
return false; | |
} | |
} | |
async function onSubmitSuccess(browser) { | |
await browser.close(); | |
} | |
async function onNoLateCertProvide(browser) { | |
await browser.close(); | |
} | |
function askQuestion(query) { | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout, | |
}); | |
return new Promise(resolve => rl.question(query, ans => { | |
rl.close(); | |
resolve(ans); | |
})) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment