Skip to content

Instantly share code, notes, and snippets.

@buptsb
Last active October 25, 2018 12:11
Show Gist options
  • Save buptsb/c580b49166e89b765d24383bfa055fbf to your computer and use it in GitHub Desktop.
Save buptsb/c580b49166e89b765d24383bfa055fbf to your computer and use it in GitHub Desktop.
toefl
const userData = {
"username": "JohnTang",
"password": "tjp1015967940",
"softid": "1",
"softkey": "b40ffbee5c1cf4e38028c197eb2fc751",
// Captcha type: 4 letters, http://www.ruokuai.com/home/pricetype
"typeid":"2040"
};
const API_URL = "http://api.ruokuai.com/create.json";
xhook.after((req, resp) => {
if(req.method == "POST" && req.url.match(/bookSeat/)) {
let text = resp.text;
if (text && text.indexOf("验证码错误") != -1) {
// retry
RequestOCR();
}
}
});
async function RequestOCR() {
const formData = new FormData();
for (const k in userData) {
const v = userData[k];
formData.append(k, v);
}
let imgBlob = await getCaptchaBlob();
formData.append("image", imgBlob, "1.jpg");
const options = {
method: "POST",
body: formData,
headers: {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0"
}
}
fetch(API_URL, options)
.then(resp => {
return resp.json();
})
.then(json => {
let result = data["Result"];
console.log(result);
if (result) {
CommitCaptcha(result);
}
})
.catch(err => {
console.log(err);
});
}
function __chottoMatte(n_millisecond) {
return new Promise(resolve => setTimeout(resolve, n_millisecond));
}
async function CommitCaptcha(ocrResult) {
const CAPTCHA_INPUT_SELECTOR = "#verifyCode";
const CAPTCHA_COMMIT_SELECTOR_1 = "#btnOrderBookSeat";
const CAPTCHA_COMMIT_SELECTOR_2 = "div.layui-layer-btn.layui-layer-btn- > a.layui-layer-btn0";
let e = document.querySelector(CAPTCHA_INPUT_SELECTOR);
e.value = ocrResult;
document.querySelector(CAPTCHA_COMMIT_SELECTOR_1).click();
await __chottoMatte(500);
document.querySelector(CAPTCHA_COMMIT_SELECTOR_2).click();
}
async function getCaptchaBlob() {
const CAPTCHA_SELECTOR = "#chkImg";
const e = document.querySelector(CAPTCHA_SELECTOR);
// trigger captcha image reload
e.click();
await __chottoMatte(1000);
// TODO: safety check
// blog-util
// captcha node
// WARN: do not omit `Anonymous` param
// Refer: https://github.com/nolanlawson/blob-util#imgsrctoblob
// `for CORS-enabled images, set this to 'Anonymous' to avoid "tainted canvas" errors`
return await blobUtil.imgSrcToBlob(e.src, "image/jpeg", "Anonymous");
}
async function __test() {
let blob = await getCaptchaBlob();
console.log(blob);
}
let _context = {
loggedIn: false
};
async function PageRedirect() {
// hard-coded url
const QUERY_SEAT_PAGE = "https://toefl.etest.net.cn/myHome/8462936/index#!/createOrder/querySeat";
const HOME_PAGE = "https://toefl.etest.net.cn/";
// user is logged out
if (document.title.indexOf("请重新登录") != -1) {
location.href = HOME_PAGE;
// returned
}
let current = location.href;
if (current != QUERY_SEAT_PAGE) {
location.href = QUERY_SEAT_PAGE;
}
$("#wg_west > li:nth-child(12) > a").click();
await __chottoMatte(300);
$("span.layui-layer-setwin > a").click();
await __chottoMatte(300);
}
async function loop() {
// 1. go to queryOrder page
PageRedirect();
// 2.
Query();
}
// regForm/showRegForm
const AVAILABLE_STATUS_SELECTOR = "#qrySeatResult > div > table > tbody > tr > td:nth-child(4)";
const CITY_SELECTOR = "#centerProvinceCity";
const DATE_SELECTOR = "#testDays";
const SEARCH_BUTTON_SELECTOR = "#btnQuerySeat"
let running = true;
function TriggerSearch() {
document.querySelector(SEARCH_BUTTON_SELECTOR).click();
}
function SetCity(n) {
document.querySelector(CITY_SELECTOR).value = n;
}
function SetDate(d) {
document.querySelector(DATE_SELECTOR).value = d;
}
function isAvailable(node) {
let keyword = "bookSeat"
let isHTMLNode = (typeof node == "object") &&
("nodeType" in node) &&
(node.nodeType === 1);
return isHTMLNode && (node.innerHTML.indexOf(keyword) != -1);
}
function Check() {
let nodes = document.querySelectorAll(AVAILABLE_STATUS_SELECTOR);
for (let node of nodes) {
if (isAvailable(node)) {
console.log(node);
return true;
}
}
return false;
}
function ChottoMatte(n_millisecond) {
return new Promise(resolve => setTimeout(resolve, n_millisecond));
}
function Notify() {
new Notification("Found!");
// alert("Found!");
}
async function loop() {
let city = ["BEIJING"],
date = ["2018-11-11", "2018-11-17", "2019-06-16"];
let permutations = [city, date].reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
let foundAvailable = false;
for (const item of permutations) {
let [city, date] = item;
if (!running) {
return;
}
SetCity(city);
SetDate(date);
TriggerSearch();
// wait for HTTP request
await ChottoMatte(1000);
if (foundAvailable = Check()) {
break;
}
// throttle request frequency
await ChottoMatte(3000);
}
if (foundAvailable) {
Notify();
} else {
await loop();
}
}
function LoopStop() {
running = false;
console.log("Stopped.");
}
async function LoopStart() {
Notification.requestPermission();
console.log("Started.");
await loop();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment