-
Allow unsafe scripts
-
Chrome extension: Allow CORS https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi
-
Chrome extension: User javascript https://chrome.google.com/webstore/detail/user-javascript-and-css/nbhcbdghjpllgmfilhnhkllmkecfmpld
-
Dependency: xhook https://github.com/jpillora/xhook
-
Dependency: blobUtil https://github.com/nolanlawson/blob-util
Last active
October 25, 2018 12:11
-
-
Save buptsb/c580b49166e89b765d24383bfa055fbf to your computer and use it in GitHub Desktop.
toefl
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 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 |
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 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