log to file
This commit is contained in:
+4
-1
@@ -28,7 +28,10 @@
|
|||||||
<option value="sevres">Hermès Sèvres</option>
|
<option value="sevres">Hermès Sèvres</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div id="device_list"/>
|
<div>
|
||||||
|
<label for="device_list">连接的手机</label>
|
||||||
|
<div id="device_list"/>
|
||||||
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<button id="start_book_btn">开始约会
|
<button id="start_book_btn">开始约会
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const createWindow = () => {
|
|||||||
startBook(startNumber, endNumber, selectedStore)
|
startBook(startNumber, endNumber, selectedStore)
|
||||||
})
|
})
|
||||||
ipcMain.handle('scan-devices', scanDevices)
|
ipcMain.handle('scan-devices', scanDevices)
|
||||||
win.webContents.openDevTools();
|
// win.webContents.openDevTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
|
|||||||
+2
-1
@@ -17,7 +17,8 @@
|
|||||||
"mongodb": "^4.9.1",
|
"mongodb": "^4.9.1",
|
||||||
"mongoose": "^6.5.4",
|
"mongoose": "^6.5.4",
|
||||||
"node-xlsx": "^0.21.0",
|
"node-xlsx": "^0.21.0",
|
||||||
"playwright": "1.23.0"
|
"playwright": "1.23.0",
|
||||||
|
"winston": "^3.8.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@electron-forge/cli": "^6.0.0-beta.66",
|
"@electron-forge/cli": "^6.0.0-beta.66",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
let startNumber = 0;
|
let startNumber = 0;
|
||||||
let endNumber = 0;
|
let endNumber = 0;
|
||||||
let selectedStore = 'faubourg';
|
let selectedStore = 'random';
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
window.appointment.scanDevices().then((deviceList) => {
|
window.appointment.scanDevices().then((deviceList) => {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
const {createLogger, format, transports} = require('winston');
|
||||||
|
const {_, formatDate} = require('../workers/mongo_manager')
|
||||||
|
const {printf, label, timestamp, combine} = format;
|
||||||
|
|
||||||
|
const myFormat = printf(({level, message, label, timestamp}) => {
|
||||||
|
return `${timestamp} [${label}] ${level}: ${message}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const appointmentLogger = createLogger({
|
||||||
|
level: 'info',
|
||||||
|
format: combine(
|
||||||
|
label({label: 'appointment'}),
|
||||||
|
timestamp(),
|
||||||
|
myFormat
|
||||||
|
),
|
||||||
|
transports: [
|
||||||
|
new transports.File({filename: "appointment_" + formatDate(new Date()) + ".log"}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = appointmentLogger
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
const {_android: android, devices} = require("playwright");
|
|
||||||
const {SolveCaptcha, TWO_CAPTCHA_CONNECTION_FAILED} = require("./SolveCaptcha");
|
const {SolveCaptcha, TWO_CAPTCHA_CONNECTION_FAILED} = require("./SolveCaptcha");
|
||||||
const ReserveResultPojo = require("../models/ReserveResultPojo");
|
const ReserveResultPojo = require("../models/ReserveResultPojo");
|
||||||
|
const appointmentLogger = require("../utiles/LoggerUtils")
|
||||||
const PublishType = require("../models/PublishType");
|
const PublishType = require("../models/PublishType");
|
||||||
const beep = require('beepbeep')
|
const beep = require('beepbeep')
|
||||||
// const RDV_URL = "http://192.168.1.16:8000/test_appointment.html"
|
const RDV_URL = "http://192.168.0.44:8000/test_appointment.html"
|
||||||
const RDV_URL = "https://rendezvousparis.hermes.com/client/register";
|
// const RDV_URL = "https://rendezvousparis.hermes.com/client/register";
|
||||||
BLANK_URL = "about:blank"
|
BLANK_URL = "about:blank"
|
||||||
const ERROR_CAPTCHA_UNSOLVABLE = "ERROR_CAPTCHA_UNSOLVABLE";
|
const ERROR_CAPTCHA_UNSOLVABLE = "ERROR_CAPTCHA_UNSOLVABLE";
|
||||||
|
|
||||||
@@ -49,6 +49,10 @@ function getRandomWaitTime() {
|
|||||||
return getRandom() * 1000
|
return getRandom() * 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function log(message) {
|
||||||
|
appointmentLogger.log({level: "info", message: message})
|
||||||
|
}
|
||||||
|
|
||||||
class CommandorPage {
|
class CommandorPage {
|
||||||
constructor(contact, device, mongoManager, selectedStore = DEFAULT_STORE) {
|
constructor(contact, device, mongoManager, selectedStore = DEFAULT_STORE) {
|
||||||
this.contact = contact;
|
this.contact = contact;
|
||||||
@@ -59,9 +63,10 @@ class CommandorPage {
|
|||||||
this.isTerminated = false;
|
this.isTerminated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async loadPage() {
|
async loadPage() {
|
||||||
// Connect to the device.
|
// Connect to the device.
|
||||||
console.log("loadPage() called");
|
log("loadPage() called");
|
||||||
await this.device.shell('am force-stop com.android.chrome');
|
await this.device.shell('am force-stop com.android.chrome');
|
||||||
const context = await this.device.launchBrowser();
|
const context = await this.device.launchBrowser();
|
||||||
// await context.clearCookies()
|
// await context.clearCookies()
|
||||||
@@ -78,14 +83,14 @@ class CommandorPage {
|
|||||||
try {
|
try {
|
||||||
await this.page.goto(RDV_URL, {timeout: 90 * 1000});
|
await this.page.goto(RDV_URL, {timeout: 90 * 1000});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
log(e)
|
||||||
this.isTerminated = true
|
this.isTerminated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let cancel
|
let cancel
|
||||||
const intervalTask = setInterval(() => {
|
const intervalTask = setInterval(() => {
|
||||||
if (this.isTerminated) {
|
if (this.isTerminated) {
|
||||||
console.log("request terminated, will close device")
|
log("request terminated, will close device")
|
||||||
context.close()
|
context.close()
|
||||||
// this.page.close()
|
// this.page.close()
|
||||||
this.device.close()
|
this.device.close()
|
||||||
@@ -100,7 +105,7 @@ class CommandorPage {
|
|||||||
fulfill(Promise.resolve())
|
fulfill(Promise.resolve())
|
||||||
}
|
}
|
||||||
setTimeout(fulfill, TIME_OUT, 5)
|
setTimeout(fulfill, TIME_OUT, 5)
|
||||||
}).then(console.log)
|
}).then(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
async chooseCountry(page) {
|
async chooseCountry(page) {
|
||||||
@@ -115,7 +120,7 @@ class CommandorPage {
|
|||||||
await page.selectOption(COUNTRY_ID, 'FR');
|
await page.selectOption(COUNTRY_ID, 'FR');
|
||||||
await delay(getRandomWaitTime())
|
await delay(getRandomWaitTime())
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
log(e);
|
||||||
this.isTerminated = true;
|
this.isTerminated = true;
|
||||||
}
|
}
|
||||||
// await page.click(COUNTRY_ID);
|
// await page.click(COUNTRY_ID);
|
||||||
@@ -130,7 +135,7 @@ class CommandorPage {
|
|||||||
await page.locator(EMAIL_ID).fill(this.contact.mail);
|
await page.locator(EMAIL_ID).fill(this.contact.mail);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
log(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +146,7 @@ class CommandorPage {
|
|||||||
await page.locator(PHONE_NUMBER).fill("0" + this.contact.phoneNumber)
|
await page.locator(PHONE_NUMBER).fill("0" + this.contact.phoneNumber)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
log(e);
|
||||||
this.isTerminated = true;
|
this.isTerminated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +163,7 @@ class CommandorPage {
|
|||||||
await page.locator(FIRST_NAME).fill(this.contact.firstName)
|
await page.locator(FIRST_NAME).fill(this.contact.firstName)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
log(e);
|
||||||
this.isTerminated = true
|
this.isTerminated = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +177,7 @@ class CommandorPage {
|
|||||||
await page.locator(PASSPORT_ID).fill(this.contact.passportNumber.toString())
|
await page.locator(PASSPORT_ID).fill(this.contact.passportNumber.toString())
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
log(e);
|
||||||
this.isTerminated = true;
|
this.isTerminated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +193,7 @@ class CommandorPage {
|
|||||||
await page.locator(PROCESSING_ID).click()
|
await page.locator(PROCESSING_ID).click()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
log(e);
|
||||||
this.isTerminated = true;
|
this.isTerminated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +201,7 @@ class CommandorPage {
|
|||||||
async chooseStore(page) {
|
async chooseStore(page) {
|
||||||
try {
|
try {
|
||||||
if (!page.isClosed()) {
|
if (!page.isClosed()) {
|
||||||
if (selectedStore !== "random") {
|
if (this.selectedStore !== "random") {
|
||||||
await page.locator(PREFER_STORE).focus()
|
await page.locator(PREFER_STORE).focus()
|
||||||
await delay(1000)
|
await delay(1000)
|
||||||
await page.click(PREFER_STORE);
|
await page.click(PREFER_STORE);
|
||||||
@@ -204,7 +209,7 @@ class CommandorPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
log(e);
|
||||||
this.isTerminated = true;
|
this.isTerminated = true;
|
||||||
}
|
}
|
||||||
// await page.click(PREFER_STORE);
|
// await page.click(PREFER_STORE);
|
||||||
@@ -212,7 +217,7 @@ class CommandorPage {
|
|||||||
|
|
||||||
|
|
||||||
async fillFields(page) {
|
async fillFields(page) {
|
||||||
console.log("fillFields called")
|
log("fillFields called")
|
||||||
if (!this.isFillingFields) {
|
if (!this.isFillingFields) {
|
||||||
this.isFillingFields = true;
|
this.isFillingFields = true;
|
||||||
await this.chooseStore(page);
|
await this.chooseStore(page);
|
||||||
@@ -243,7 +248,7 @@ class CommandorPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
log(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +259,7 @@ class CommandorPage {
|
|||||||
}
|
}
|
||||||
this.captchaSolver = new SolveCaptcha(page);
|
this.captchaSolver = new SolveCaptcha(page);
|
||||||
await this.captchaSolver.start((solution) => {
|
await this.captchaSolver.start((solution) => {
|
||||||
console.log("solution is: " + solution);
|
log("solution is: " + solution);
|
||||||
if (solution !== ERROR_CAPTCHA_UNSOLVABLE && solution !== TWO_CAPTCHA_CONNECTION_FAILED) {
|
if (solution !== ERROR_CAPTCHA_UNSOLVABLE && solution !== TWO_CAPTCHA_CONNECTION_FAILED) {
|
||||||
try {
|
try {
|
||||||
if (!page.isClosed()) {
|
if (!page.isClosed()) {
|
||||||
@@ -266,7 +271,7 @@ class CommandorPage {
|
|||||||
this.clickValid();
|
this.clickValid();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
log(e)
|
||||||
this.isTerminated = true;
|
this.isTerminated = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -282,7 +287,7 @@ class CommandorPage {
|
|||||||
if (content.toString().includes(captcha_url)) {
|
if (content.toString().includes(captcha_url)) {
|
||||||
await this.checkAudioBtn();
|
await this.checkAudioBtn();
|
||||||
beep(20)
|
beep(20)
|
||||||
console.log("发现datadome");
|
log("发现datadome");
|
||||||
} else {
|
} else {
|
||||||
if (currentPage.url() === RDV_URL) {
|
if (currentPage.url() === RDV_URL) {
|
||||||
await this.fillFields(this.page);
|
await this.fillFields(this.page);
|
||||||
@@ -290,7 +295,7 @@ class CommandorPage {
|
|||||||
await this.getErrors()
|
await this.getErrors()
|
||||||
} else {
|
} else {
|
||||||
if (content.includes(MESSAGE_URL_VALIDATION_FR) || content.includes(MESSAGE_URL_VALIDATION_EN)) {
|
if (content.includes(MESSAGE_URL_VALIDATION_FR) || content.includes(MESSAGE_URL_VALIDATION_EN)) {
|
||||||
console.log("successful");
|
log("successful");
|
||||||
await this.push_message_to_queue(PublishType.SUCCESS);
|
await this.push_message_to_queue(PublishType.SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
// try to get errors
|
// try to get errors
|
||||||
@@ -304,17 +309,17 @@ class CommandorPage {
|
|||||||
// let iframe = await this.page.locator("iframe").contentFrame;
|
// let iframe = await this.page.locator("iframe").contentFrame;
|
||||||
// let audioBtn = iframe.locator("#captcha__audio__button");
|
// let audioBtn = iframe.locator("#captcha__audio__button");
|
||||||
// if (audioBtn) {
|
// if (audioBtn) {
|
||||||
// console.log("audioBtn found")
|
// log("audioBtn found")
|
||||||
// } else {
|
// } else {
|
||||||
// console.log("audioBtn not found")
|
// log("audioBtn not found")
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
async onResponse(response) {
|
async onResponse(response) {
|
||||||
// let rex = new RegExp(REGEX_RDV_URL)
|
// let rex = new RegExp(REGEX_RDV_URL)
|
||||||
// console.log("onResponse with url:" + response.url())
|
// log("onResponse with url:" + response.url())
|
||||||
// if (rex.test(response.url())) {
|
// if (rex.test(response.url())) {
|
||||||
// console.log("rdv url found:" + response.url())
|
// log("rdv url found:" + response.url())
|
||||||
// await this.push_message_to_db(PublishType.SUCCESS, response.url())
|
// await this.push_message_to_db(PublishType.SUCCESS, response.url())
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
@@ -356,11 +361,11 @@ class CommandorPage {
|
|||||||
let errorItem = this.page.locator("div.alert");
|
let errorItem = this.page.locator("div.alert");
|
||||||
if (errorItem) {
|
if (errorItem) {
|
||||||
let errorContent = await errorItem.innerHTML();
|
let errorContent = await errorItem.innerHTML();
|
||||||
console.log("error:" + errorContent);
|
log("error:" + errorContent);
|
||||||
this.handleError(errorContent);
|
this.handleError(errorContent);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user