452 lines
13 KiB
JavaScript
452 lines
13 KiB
JavaScript
// Interencheres.js
|
|
'use strict';
|
|
const {Scraper} = require('../Scraper');
|
|
const DrouotData = require('./DrouotData');
|
|
|
|
class Drouot extends Scraper {
|
|
|
|
constructor(Url) {
|
|
super(Url);
|
|
|
|
this.platformData = new DrouotData();
|
|
|
|
this.platformData.getUrlInfo(Url).then((data) => {
|
|
if(data.lotID == 0 && data.saleID == 0){
|
|
throw new Error('Invalid URL');
|
|
}
|
|
});
|
|
|
|
this._Name = 'drouot'
|
|
this._PAGE_MAIN = "https://drouot.com/fr/"
|
|
this._PAGE_LOGIN = "https://auth.drouot.com/login"
|
|
|
|
this._USER = "jp.ranu@cogip.de"
|
|
this._PWD = "LYPYRKDUsSMH5BaWQxvH#"
|
|
this._PATH_SESSION_FILE = ".session/session_drouot.json"
|
|
this._PATH_PROTOBUF_FILE = "./AuctionServices/Scraper/Drouot/drouot.proto"
|
|
this._BROWSER_TOOL = "playwrightBrowser"
|
|
}
|
|
|
|
getPictures = async ({ page, data}) => {
|
|
|
|
const PictList = await this.platformData.getPictures(page, this.Url);
|
|
console.log('PictList : '+PictList)
|
|
return PictList
|
|
}
|
|
|
|
getLotInfos = async ({ page, data}) => {
|
|
|
|
console.log("getLotInfos "+this._Name+": "+this.Url)
|
|
|
|
// Navigate the page to a URL
|
|
await page.goto(this.Url);
|
|
|
|
let idLot = await this.platformData.getLotID(this.Url);
|
|
console.log('idLot : '+idLot)
|
|
|
|
// ## LotNumber
|
|
let lotNumber = await this.platformData.getLotNumber(page);
|
|
console.log('lotNumber : '+lotNumber)
|
|
|
|
// ## Title
|
|
let title = await this.platformData.getLotTitle(page);
|
|
console.log('title : '+title)
|
|
|
|
// ## Estimate
|
|
let {EstimateLow, EstimateHigh} = await this.platformData.getEstimate(page);
|
|
console.log('EstimateLow : '+EstimateLow)
|
|
|
|
// ## Description
|
|
let Description = await this.platformData.getDescription(page);
|
|
//console.log('Description : '+Description)
|
|
|
|
// ## Fees
|
|
let {feesText, fees} = await this.platformData.getFees(page);
|
|
|
|
console.log('feesText : '+feesText)
|
|
console.log('fees : '+fees)
|
|
|
|
// ################
|
|
// ### SALE
|
|
|
|
let {id_sale, urlSale} = await this.platformData.getSaleID(page);
|
|
|
|
console.log('SellNumber : '+id_sale)
|
|
|
|
|
|
console.log('url : '+urlSale)
|
|
|
|
let LotInfos = {
|
|
idPlatform: idLot,
|
|
platform : this._Name,
|
|
url: this.Url,
|
|
title: title,
|
|
lotNumber: lotNumber,
|
|
EstimateLow: EstimateLow,
|
|
EstimateHigh: EstimateHigh,
|
|
Description: Description,
|
|
feesText: feesText,
|
|
fees: fees,
|
|
saleInfo: {
|
|
idSale: id_sale,
|
|
url: urlSale
|
|
}
|
|
}
|
|
|
|
console.log('LotInfos : '+LotInfos)
|
|
|
|
return LotInfos
|
|
}
|
|
|
|
getSaleInfos = async ({ page, data}) => {
|
|
console.log("getSaleInfos "+this._Name+": "+this.Url)
|
|
|
|
// Navigate the page to a URL
|
|
await page.goto(this.Url);
|
|
|
|
let {saleID, urlSale} = await this.platformData.getUrlInfo(this.Url);
|
|
|
|
console.log('saleID : '+saleID)
|
|
console.log('urlSale : '+urlSale)
|
|
|
|
// ## Title
|
|
let title = await this.platformData.getSaleTitle(page);
|
|
console.log('title : '+title)
|
|
|
|
// ## Date
|
|
let date = await this.platformData.getSaleDate(page);
|
|
console.log('date : '+date)
|
|
|
|
// ## Location
|
|
let location = await this.platformData.getSaleLocation(page);
|
|
console.log('location : '+location)
|
|
|
|
// ## SaleHouseName
|
|
let saleHouseName = await this.platformData.getSaleHouseName(page);
|
|
console.log('saleHouseName : '+saleHouseName)
|
|
|
|
// ## Status
|
|
// ready : ready to be followed
|
|
// following : sale is followed by the AuctionAgent
|
|
// askStop : sale is followed by the AuctionAgent and the user ask to stop following
|
|
// pause : the Sale is stopped by the Auction House and ready to restart
|
|
// end : the Sale is ended
|
|
|
|
let status = 'ready'
|
|
|
|
let SaleInfo = {
|
|
idPlatform: saleID,
|
|
platform : this._Name,
|
|
url: urlSale,
|
|
title: title,
|
|
date: date,
|
|
location: location,
|
|
saleHouseName: saleHouseName,
|
|
status: status
|
|
}
|
|
|
|
console.log('SaleInfo : ', JSON.stringify(SaleInfo, null, 2));
|
|
return SaleInfo
|
|
}
|
|
|
|
getLotList = async ({ page, data}) => {
|
|
console.log("getLotList "+this._Name+": "+this.Url)
|
|
|
|
// Navigate the page to a URL
|
|
await page.goto(this.Url);
|
|
|
|
const LotList = await this.platformData.getLotList(page);
|
|
console.log('LotList : '+LotList)
|
|
return LotList
|
|
}
|
|
|
|
// ### Playwright
|
|
// ###########################################################################
|
|
|
|
async CheckCookieDialog(page) {
|
|
console.log("-- CheckCookieDialog --")
|
|
return new Promise(async (resolve, reject) => {
|
|
|
|
//let XpathCookieButton = "xpath=//button[contains(@class, 'rgpd') and contains(text(), 'Tout refuser')"
|
|
// const CookieButton = await page.$$(XpathCookieButton);
|
|
const CookieButton = await page.$('//button[contains(@class, "rgpd") and contains(text(), "Tout refuser")]');
|
|
//console.log(CookieButton)
|
|
if (CookieButton && await CookieButton.isVisible()) {
|
|
console.log("-- Click on CookieButton --")
|
|
await CookieButton.click();
|
|
}
|
|
|
|
resolve(true)
|
|
})
|
|
}
|
|
|
|
async CheckAndConnect(page) {
|
|
|
|
return new Promise(async (resolve, reject) => {
|
|
|
|
await page.goto(this._PAGE_MAIN);
|
|
|
|
await this.CheckCookieDialog(page);
|
|
|
|
console.log("-- CheckConnexion --")
|
|
//get the Connexion button
|
|
|
|
let XpathConnexion = "//div[contains(@class, 'btn') and contains(@class, 'ghost') and contains(text(), 'Connexion')]"
|
|
const Connexion = await page.$$(XpathConnexion);
|
|
|
|
// if Connection button found => Login
|
|
if (Connexion.length > 0) {
|
|
console.log("-- Login --")
|
|
|
|
await page.goto(this._PAGE_LOGIN);
|
|
|
|
//get the Email field
|
|
//console.log("-- get Email Input --")
|
|
//await page.type('#email', this._USER);
|
|
await page.fill('#email', this._USER);
|
|
|
|
//console.log("-- get password Input --")
|
|
//wait page.type("#password", this._PWD);
|
|
await page.fill('#password', this._PWD);
|
|
|
|
//await page.screenshot({ path: 'screenshot.png', fullPage: true });
|
|
|
|
//console.log("-- get ConnexionButton --")
|
|
//const [ConnexionButton] = await page.$x("//button[contains(text(), 'Connexion')]");
|
|
//await ConnexionButton.evaluate(b => b.click());
|
|
await page.click("//button[contains(text(), 'Connexion')]");
|
|
|
|
//console.log("-- Login wait --")
|
|
await page.waitForTimeout(1000);
|
|
//resolve(page)
|
|
|
|
const ConnexionOK = await page.$$("//button[contains(text(), 'Continuer en tant que')]");
|
|
//console.log(ConnexionOK)
|
|
if (ConnexionOK.length > 0) {
|
|
|
|
//await ConnexionOK.screenshot({ path: 'screenshot.png', fullPage: true });
|
|
|
|
//await ConnexionOK.evaluate(b => b.click());
|
|
await ConnexionOK[0].click();
|
|
await page.waitForTimeout(1000);
|
|
|
|
await this._saveSession(page)
|
|
|
|
console.log("-- Connection OK --")
|
|
resolve(page)
|
|
} else {
|
|
console.error("-- !!!! Connection ERROR !!!! --");
|
|
reject()
|
|
}
|
|
|
|
// Allready connected
|
|
} else {
|
|
console.log("-- Allready connected --")
|
|
resolve(page)
|
|
}
|
|
})
|
|
|
|
}
|
|
|
|
Live = async (browser) => {
|
|
|
|
const context = await this._getContext(browser);
|
|
|
|
console.log("Live "+this._Name+": "+this.Url)
|
|
|
|
let page = await context.newPage();
|
|
|
|
page = await this.CheckAndConnect(page);
|
|
|
|
//init Protobuf Decoder
|
|
const protobuf = require("protobufjs");
|
|
const root = await protobuf.load(this._PATH_PROTOBUF_FILE);
|
|
const LiveBiddingMessage = root.lookupType("drouot.LiveBiddingMessage");
|
|
|
|
const listener = async (params) => {
|
|
|
|
let buffer = params.payload;
|
|
|
|
const err = LiveBiddingMessage.verify(buffer);
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
const message = LiveBiddingMessage.decode(buffer);
|
|
const BideMessage = LiveBiddingMessage.toObject(message, {enums: String});
|
|
|
|
let DataLot = null
|
|
if(BideMessage.vente && BideMessage.vente.lot && BideMessage.vente.lot.lotId != undefined){
|
|
DataLot = await this.platformData.getLiveDataLot(BideMessage.vente.lot.lotId);
|
|
}
|
|
//console.log('BideMessage Type: '+BideMessage.type+' Lot: '+BideMessage.vente.lot.lotId);
|
|
|
|
switch (BideMessage.type) {
|
|
case 'PING':
|
|
break;
|
|
case 'PONG':
|
|
break;
|
|
case 'INIT':
|
|
console.log('INIT');
|
|
|
|
break;
|
|
case 'CLOSE':
|
|
console.log('CLOSE');
|
|
|
|
break;
|
|
case 'BID':
|
|
console.log('BID');
|
|
console.log('Lot: '+BideMessage.vente.lot.lotId+' Amount: '+BideMessage.vente.bid.amount);
|
|
|
|
await this.JucundusBid(
|
|
BideMessage.vente.lot.lotId,
|
|
Date.now(),
|
|
BideMessage.vente.bid.amount,
|
|
BideMessage.vente.bid.type
|
|
);
|
|
break;
|
|
|
|
case 'SELECT_LOT':
|
|
console.log('SELECT_LOT');
|
|
console.log('Lot: '+BideMessage.vente.lot.lotId);
|
|
|
|
//console.log('DataLot : '+DataLot)
|
|
|
|
await this.JucunduNextItem(
|
|
BideMessage.vente.venteId,
|
|
Date.now(),
|
|
BideMessage.vente.lot.lotId,
|
|
DataLot.num,
|
|
DataLot.titre,
|
|
DataLot.description,
|
|
DataLot.estimationBasse,
|
|
DataLot.estimationHaute,
|
|
DataLot
|
|
);
|
|
|
|
break;
|
|
case 'STARTING_PRICE':
|
|
console.log('STARTING_PRICE');
|
|
|
|
await this.JucunduNextItem(
|
|
BideMessage.vente.venteId,
|
|
Date.now(),
|
|
BideMessage.vente.lot.lotId,
|
|
DataLot.num,
|
|
DataLot.titre,
|
|
DataLot.description,
|
|
DataLot.estimationBasse,
|
|
DataLot.estimationHaute,
|
|
DataLot
|
|
);
|
|
|
|
break;
|
|
case 'INCREMENT':
|
|
console.log('INCREMENT');
|
|
break;
|
|
|
|
case 'TENDERING':
|
|
console.log('TENDERING');
|
|
console.log('Lot: '+BideMessage.vente.lot.lotId+' Amount: '+BideMessage.vente.bid.amount);
|
|
|
|
await this.JucunduAuctionedItem(
|
|
BideMessage.vente.lot.lotId,
|
|
Date.now(),
|
|
BideMessage.vente.bid.amount,
|
|
BideMessage.vente.lot.state == 'ADJ' ? true : false,
|
|
BideMessage.vente.bid.type
|
|
);
|
|
|
|
break;
|
|
|
|
case 'GENERIC_MESSAGE':
|
|
console.log('GENERIC_MESSAGE');
|
|
break;
|
|
case 'CREATE_LOT':
|
|
console.log('CREATE_LOT');
|
|
break;
|
|
case 'NOT_INTERESTED':
|
|
break;
|
|
case 'INTERESTED':
|
|
break;
|
|
case 'ACTIVITY':
|
|
break;
|
|
case 'NEW_CLIENT':
|
|
console.log('NEW_CLIENT');
|
|
break;
|
|
case 'CLOSED_CLIENT':
|
|
break;
|
|
case 'KILL':
|
|
break;
|
|
case 'MULTILOT_REQUEST':
|
|
break;
|
|
case 'MULTILOT_RESPONSE':
|
|
break;
|
|
case 'SYNC_PAYMENT_LIMIT':
|
|
break;
|
|
case 'SWITCH_FREE_BID_AUTHORIZE':
|
|
break;
|
|
case 'REFRESH_CLIENTS_COUNT':
|
|
console.log('REFRESH_CLIENTS_COUNT');
|
|
break;
|
|
default:
|
|
//console.log('Unknown type:', BideMessage);
|
|
}
|
|
|
|
};
|
|
|
|
// create the live URL
|
|
let {saleID} = await this.platformData.getUrlInfo(this.Url);
|
|
let UrlLive = this._PAGE_MAIN + "live/bidlive/" + saleID;
|
|
|
|
let CheckAskStop = null;
|
|
let Socket = null;
|
|
|
|
// Stop the Live
|
|
const StopLive = async (params) => {
|
|
clearInterval(CheckAskStop);
|
|
page.close()
|
|
browser.close()
|
|
}
|
|
|
|
try{
|
|
console.log('UrlLive : '+UrlLive)
|
|
|
|
await page.goto(UrlLive, { waitUntil: 'domcontentloaded' });
|
|
|
|
// intercept Lots Data
|
|
await page.route('https://api.drouot.com/drouot/gingolem/api/live/venteInfos/'+saleID+'?lang=fr', async route => {
|
|
console.log('GetLiveData')
|
|
const response = await route.fetch();
|
|
const LotData = await response.json();
|
|
this.platformData.setLiveData(LotData.data);
|
|
route.continue();
|
|
});
|
|
|
|
page.on('websocket', ws => {
|
|
Socket = ws;
|
|
Socket.on('framereceived', listener);
|
|
console.log('Websocket connected');
|
|
});
|
|
|
|
console.log('UrlLive : reload')
|
|
await page.reload();
|
|
|
|
// check if stop was asked
|
|
CheckAskStop = setInterval(async () => {
|
|
this.JucundusCheckStop()
|
|
.then(AskStop => {
|
|
if(AskStop){
|
|
StopLive()
|
|
}
|
|
})
|
|
}, 10000); // 10000 milliseconds = 10 seconds
|
|
|
|
}catch(e){
|
|
console.log('Error : '+e)
|
|
throw new Error('Error: '+e)
|
|
}
|
|
|
|
}
|
|
};
|
|
|
|
module.exports = Drouot |