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.
511 lines
18 KiB
JavaScript
511 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 = await this.getText(this.mainPage, 'div.info-columns mee-rewards-counter-animation span');
|
|
console.log('> Current point :', point);
|
|
|
|
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 = statusOrder.splice(1);
|
|
// TODO: check for level 1 status
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
} |