You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

516 lines
18 KiB
JavaScript

const puppeteer = require('puppeteer');
const fs = require("fs")
const iPhonex = puppeteer.devices['iPhone X'];
const fetch = require('node-fetch');
// const RND_SLEEP_PAD_MAX = 10;
const RND_SLEEP_PAD_MAX = 1;
const MAIN_URL = 'https://rewards.bing.com/?lang=en-US';
let sleep = (sec) => {
return new Promise(resolve => setTimeout(resolve, sec * 1000));
}
async function rndSleep(sec, pad = null) {
if (!pad)
pad = Math.random() * RND_SLEEP_PAD_MAX;
await sleep(sec + pad);
}
let rndSample = (arr, n) => {
const shuffled = arr.sort(() => 0.5 - Math.random());
return shuffled.slice(0, n);
}
let shuffleArray = (array) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
module.exports = class BingAuto2 {
constructor(id, pw, headless) {
this.id = id;
this.pw = pw;
this.headless = headless;
this.browser = null;
this.mainPage = null;
this.keywords = null;
}
async startBrowser() {
let id = this.id.split('@')[0];
let tmp_dir = './chrome_cache_' + id;
if (!fs.existsSync(tmp_dir))
fs.mkdirSync(tmp_dir);
// await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36');
let option = {
headless: this.headless,
userDataDir: tmp_dir,
args: ["--proxy-server='direct://'", '--proxy-bypass-list=*', '--disable-site-isolation-trials', '--no-sandbox']
};
this.browser = await puppeteer.launch(option);
// await browser.close();
}
async close() {
this.browser.close();
}
async newPage(agent = 'chrome') {
let browser = this.browser;
const page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36');
// await page.setCacheEnabled(false);
// await page.setDefaultNavigationTimeout(0);
if (agent === 'mobile')
await page.emulate(iPhonex);
else
await page.setViewport({height: 900, width: 1200});
if (agent === 'edge') {
await page.setUserAgent('"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/83.0.2704.79 Safari/537.36 Edge/14.14931"')
}
await page.goto(MAIN_URL);
return page;
}
async newMainPage(login = true) {
this.mainPage = await this.newPage();
if (login)
await sleep(1);
await this.login();
}
async login() {
let page = this.mainPage;
let elem, elems;
await page.waitForSelector('body');
elem = await page.$('div.info-columns mee-rewards-counter-animation span');
if (elem)
return;
console.log('> Logging In...');
// elem = await page.$('#raf-signin-link-id');
// console.log('> Logging In...0');
// if (elem == null)
// return;
//
// await elem.click();
// await page.waitForNavigation({waitUntil: 'networkidle0'});
elem = await page.$('[name="loginfmt"]');
await elem.type(this.id);
await elem.press('Enter');
await sleep(2);
elem = await page.$('[name="KMSI"]');
if (elem)
elem.click();
await sleep(1);
elem = await page.$('[name="passwd"]');
await elem.type(this.pw);
await elem.press('Enter');
await sleep(3);
elem = await page.$('#iLooksGood');
if (elem) {
await elem.click();
await sleep(1);
await page.waitForNavigation();
}
elem = await page.$('#KmsiCheckboxField');
if (elem) {
elem.click();
elem = await page.$('#idSIButton9');
elem.click();
await sleep(4);
}
// check language error
elem = await page.$('#error-links > li > a');
if (elem)
elem.click();
console.log('> Logged In');
}
async getRewardPoint() {
if (this.mainPage.url() !== MAIN_URL) {
await this.mainPage.goto(MAIN_URL);
}
await sleep(5);
let point = '0';
try {
let point = await this.getText(this.mainPage, 'div.info-columns mee-rewards-counter-animation span');
console.log('> Current point :', point);
} catch (e) {
console.log('Failed to get point');
return 0;
}
return parseInt(point.replace(',', ''));
}
async doDailyReward() {
console.log('> Daily Reward');
if (this.mainPage.url() !== MAIN_URL)
await this.mainPage.goto(MAIN_URL);
let cards = await this.mainPage.$$('#daily-sets mee-card');
cards.splice(3);
cards = cards.concat(await this.mainPage.$$('#more-activities mee-card'));
// console.log(cards.length + ' cards');
for (let card of cards) {
let newPage = null;
try {
if (!await card.$('.mee-icon-AddMedium') && !await card.$('.mee-icon-HourGlass'))
continue;
let title = await this.getText(this.mainPage, '.contentContainer > h3', card);
console.log('Card: [' + title + ']');
let elem = await card.$('div.actionLink');
await this.click(this.mainPage, elem);
await sleep(3);
let pages = await this.browser.pages();
if (pages.length === 2) // no new page
continue
newPage = pages[pages.length - 1];
await newPage.setViewport({height: 900, width: 1200});
await sleep(2);
await newPage.waitForSelector('body');
if (await newPage.$('.wk_paddingBtm'))
await this.doABCQuiz(newPage);
else if (await newPage.$('#rqStartQuiz'))
await this.doSelectQuiz(newPage);
else if (await newPage.$('.rqOption,.b_slidebar'))
await this.doSelectQuiz(newPage);
else {
console.log('Unknown card type');
}
} catch (e) {
console.log(e);
} finally {
if (newPage && !newPage.isClosed())
await newPage.close();
}
await rndSleep(2);
console.log('');
}
}
async getText(page, selector, elem = null) {
if (elem) {
return await page.evaluate((selector, elem) => elem.querySelector(selector).textContent, selector, elem);
} else {
return await page.evaluate((selector) => document.querySelector(selector).textContent, selector);
}
}
async checkRemainDailyReward() {
let elems = await this.mainPage.$$('#daily-sets mee-rewards-points .mee-icon-AddMedium');
let daily_remains = elems.length;
console.log(`Daily set : ${daily_remains} remains`);
elems = await this.mainPage.$$('#more-activities mee-card .mee-icon-AddMedium');
let more_remains = elems.length;
console.log(`More activities : ${more_remains} remains`);
return [daily_remains, more_remains];
}
async doABCQuiz(page) {
console.log('> ABC Quiz');
while (true) {
let answers = await page.$$('.wk_paddingBtm');
if (answers.length === 0) {
console.log('ERROR: Failed to get ABC quiz answer elements');
return;
}
let rnd_answer = Math.floor(Math.random() * answers.length);
await answers[rnd_answer].click();
await rndSleep(2);
let elem = await page.$('input[value="Next question"]');
if (elem) {
await this.click(page, elem);
} else {
elem = await page.$('input[value="Get your score"]');
if (elem) await this.click(page, elem);
break;
}
await rndSleep(2);
}
}
async doSelectQuiz(page) {
console.log('> Select Quiz');
await sleep(5);
let elem = await page.$('#rqStartQuiz');
if (elem) await this.click(page, elem);
await rndSleep(4);
elem = await page.$('.rqDragOption');
if (elem) { // order type quiz
console.log('Order-type quiz');
while (true) {
await rndSleep(5);
await this.insertDragDropFunc(page);
await rndSleep(1);
elem = await page.$('#quizCompleteContainer > div:nth-child(1) > div.headerMessage');
if (elem) {
console.log('Done');
break;
}
let all_answers = await page.$$('.rqDragOption');
let correct_ans = await page.$$('.rqDragOption.correctAnswer');
let answers = [];
for (let an of all_answers) {
if (!correct_ans.includes(an))
answers.push(an);
}
let switchAns = rndSample(answers, 2);
let ans1 = await switchAns[0].getProperty('id');
let ans2 = await switchAns[1].getProperty('id');
let js = 'triggerDragAndDrop("#","#")'
await page.evaluate((id1, id2) => {
triggerDragAndDrop('#' + id1, '#' + id2);
}, ans1, ans2);
}
} else { // select quiz
// poll
if (await page.$('#btPollOverlay')) {
console.log('Daily Poll');
let opt = await page.$('#btPollOverlay .btOption');
if (opt) {
opt.click();
await rndSleep(3);
}
return;
}
//else
const quizTypeData = [{
'type': 0,
'name': 'basic',
'tester': '#QuizContainerWrapper .rqOption',
'title': '.rqQuestion',
'btn': '#QuizContainerWrapper .rqOption'
},
{
'type': 1,
'name': 'many',
'tester': '#QuizContainerWrapper .b_slidebar',
'title': '.rqQuestion > .bt_queText',
'btn': '#QuizContainerWrapper .bt_lstcl_card'
},
{
'type': 2,
'name': 'thisthat',
'tester': '#QuizContainerWrapper .btOptionCard',
'title': '#QuizContainerWrapper .bt_Quefooter',
'btn': '#QuizContainerWrapper .btOptionCard'
}];
let elem, elems;
let quizType = -1;
for (let item of quizTypeData) {
elems = await page.$$(item['tester']);
if (elems.length !== 0) {
quizType = item['type'];
break;
}
}
if (quizType === -1) {
console.log('ERROR: Can\'t get select quiz type');
return;
}
let quizData = quizTypeData[quizType];
console.log('Quiz Type:', quizData['name']);
let btns = await page.$$(quizData['btn']);
let answerCnt = btns.length;
let intervalTime = 5;
if (quizType === 1)
answerCnt = 8;
else if (quizType === 2)
intervalTime = 10;
console.log('# of answers:', answerCnt);
while (true) {
await rndSleep(intervalTime);
elem = await page.$('#quizCompleteContainer > div:nth-child(1) > div.headerMessage');
if (elem) break;
elem = await page.$('.headerMessage_Refresh');
if (elem) break;
let answerIds = [...Array(answerCnt).keys()];
shuffleArray(answerIds);
let i = 0;
let oldTitle = await this.getText(page, quizData['title']);
while (i < answerCnt && i < 10) {
elems = await page.$$(quizData['btn']);
console.log('- Selecting answer#', answerIds[i]);
await this.elemCoordinateClick(page, elems[answerIds[i]]);
await rndSleep(intervalTime);
let newTitle = await this.getText(page, quizData['title']);
if (oldTitle !== newTitle) {
break;
}
i += 1;
}
}
}
}
async click(page, elem) {
await page.evaluate((elem) => elem.click(), elem);
}
async insertDragDropFunc(page) {
let js = 'window.triggerDragAndDrop=function(e,o){var t=function(e,o,t,r){var n=document.createEvent("MouseEvents");n.initMouseEvent(e,!0,!0,window,1,1,1,t,r,!1,!1,!1,!1,0,o),o.dispatchEvent(n)},r=document.querySelector(e),n=document.querySelector(o);if(!r||!n)return!1;var u=r.getBoundingClientRect(),a=Math.floor((u.left+u.right)/2),d=Math.floor((u.top+u.bottom)/2);u=n.getBoundingClientRect();var m=Math.floor((u.left+u.right)/2),g=Math.floor((u.top+u.bottom)/2);return t("mousemove",r,a,d),t("mouseenter",r,a,d),t("mouseover",r,a,d),t("mousedown",r,a,d),t("dragstart",r,a,d),t("drag",r,a,d),t("mousemove",r,a,d),t("drag",r,m,g),t("mousemove",n,m,g),t("mouseenter",n,m,g),t("dragenter",n,m,g),t("mouseover",n,m,g),t("dragover",n,m,g),t("drop",n,m,g),t("dragend",r,m,g),t("mouseup",r,m,g),!0};';
await page.addScriptTag({content: js});
}
async elemCoordinateClick(page, elem) {
await page.evaluate((elem) => {
let rect = elem.getBoundingClientRect();
let obj = document.elementFromPoint(rect.x + 10, rect.y + 10);
obj.click();
}, elem);
}
async getSearchKeywords() {
let getKeyword = (url, regex) => {
return new Promise(resolve => {
let args = {headers: {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36'}};
fetch(url, args)
.then(res => res.text())
.then(html => {
let matches = html.matchAll(regex);
let keywords = [];
for (let item of matches)
keywords.push(item[1]);
resolve(keywords);
});
});
}
if (this.keywords !== null)
return this.keywords;
let key1 = await getKeyword('https://datalab.naver.com/keyword/realtimeList.naver', '<span class="item_title">(.*?)</span>');
let key2 = await getKeyword('https://trends.google.com/trends/trendingsearches/daily/rss?geo=US', '<title>(.*?)</title>');
let keywords = key1.concat(key2);
if (keywords.length < 80) {
let mixes = [];
for (let i = keywords.length; i < 80; i++) {
let joins = rndSample(keywords, 2);
mixes.push(joins.join(' '));
}
keywords = keywords.concat(mixes);
}
this.keywords = keywords;
return keywords;
}
async doSearch(searchCnt = 30, page = null) {
let keywords = await this.getSearchKeywords();
if (!page)
page = this.mainPage;
await page.goto('https://www.bing.com/');
shuffleArray(keywords);
searchCnt += Math.floor(Math.random() * 10);
for (let i = 0; i < searchCnt; i++) {
try {
console.log(`Search ${i + 1}/${searchCnt} : ${keywords[i]}`);
let searchBar = await page.$('#sb_form_q');
// clear
await searchBar.click({clickCount: 3});
await searchBar.press('Backspace');
await searchBar.type(keywords[i], {delay: 200});
await searchBar.press('Enter');
await rndSleep(2);
// await rndSleep(5, 10);
} catch (e) {
console.log(e);
}
}
}
async checkSearchStatus() {
// await this.mainPage.waitForNavigation({waitUntil: "networkidle2"} );
await this.mainPage.goto('https://rewards.bing.com/pointsbreakdown');
await sleep(2);
let elems = await this.mainPage.$$('div.cardContainer p.pointsDetail');
let status = {};
let statusOrder = ['chrome', 'mobile', 'edge'];
if (elems.length === 2)
statusOrder.splice(1, 1);
for (let i = 0; i < elems.length; i++) {
let elem = elems[i];
let text = await this.mainPage.evaluate((elem) => elem.textContent, elem);
text = text.split('/');
status[statusOrder[i]] = [parseInt(text[0]), parseInt(text[1])];
}
return status;
}
async doAllSearch() {
let searchStatus = await this.checkSearchStatus();
console.log('> Search status:', searchStatus);
for (let searchType in searchStatus) {
let searchCnt = Math.floor((searchStatus[searchType][1] - searchStatus[searchType][0]) / 5);
if (searchCnt !== 0) {
console.log('>', searchType, 'search');
let page = await this.newPage(searchType);
await this.doSearch(searchCnt, page);
await page.close();
}
}
}
}