Skip to content

Instantly share code, notes, and snippets.

@ericksli
Created February 10, 2019 09:31
Show Gist options
  • Save ericksli/85306bd0669c93c18ebe369d8307e88b to your computer and use it in GitHub Desktop.
Save ericksli/85306bd0669c93c18ebe369d8307e88b to your computer and use it in GitHub Desktop.
Fill in the MTR late cert form usling puppeteer.
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