// Scraper.js 'use strict'; const fs = require('node:fs'); const fetch = require('node-fetch'); class Scraper { _Name = "" _Browser = null _PAGE_MAIN = "" _PAGE_LOGIN = "" _USER = "" _PWD = "" _PATH_SESSION_FILE = "" _BROWSER_TOOL = null _Proxy = "" _DebugMode = false _JucundusUrl = "http://host.docker.internal:3000" constructor(Url) { this.Url = Url; } async _getContext(browser) { return new Promise(async (resolve, reject) => { try { if (fs.existsSync(this._PATH_SESSION_FILE)) { resolve(await browser.newContext({ storageState: this._PATH_SESSION_FILE, timezoneId: 'Europe/Paris', extraHTTPHeaders: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0', 'Accept-Language': 'fr-FR,fr;q=0.9' } })); } else { resolve(await browser.newContext({ timezoneId: 'Europe/Paris', extraHTTPHeaders: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0', 'Accept-Language': 'fr-FR,fr;q=0.9' } })); } }catch(e){ console.error('Error: '+e) reject(new Error('Error: '+e)) } }) } async _saveSession(page) { return new Promise(async (resolve, reject) => { console.log('-- Save Session --') await page.context().storageState({ path: this._PATH_SESSION_FILE }); resolve(page) }) } getPictures({ page, data}) { } getLotInfos({ page, data}) {} getSaleInfos({ page, data}) {} getLotList({ page, data}) {} async Live({ page, data}) {} async JucundusCheckStop(){ //console.log('Check if Stop is asked') // check if stop was asked let url = encodeURIComponent(this.Url) return new Promise((resolve, reject) => { fetch(this._JucundusUrl+'/api/sale/getByUrl/'+url) .then(response => response.json()) .then(saleInfo => { let status = saleInfo.status //console.log('status : '+status) if(status == 'askStop'){ console.log('Stop was asked') // return to ready status this.JucundusSetSaleStatus(saleInfo, 'ready') .then( resolve(true) ); } else { resolve(false); } }) .catch(error => { console.error(error); reject(new Error('Error: '+error)) }); }) } async JucundusEndSale(){ console.log('JucundusEndSale') // check if stop was asked let url = encodeURIComponent(this.Url) return new Promise((resolve, reject) => { fetch(this._JucundusUrl+'/api/sale/getByUrl/'+url) .then(response => response.json()) .then(saleInfo => { // set end status this.JucundusSetSaleStatus(saleInfo, 'end') .then( resolve(true) ); }) .catch(error => { console.error(error); reject(new Error('Error: '+error)) }); }) } async JucundusSetSaleStatus(saleInfo, status){ // change the status of the sale saleInfo.status = status return new Promise((resolve, reject) => { fetch(this._JucundusUrl+'/api/sale/sale/'+saleInfo._id, { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(saleInfo)}) .then(resolve(true)) .catch(error => { console.error(error); reject(new Error('Error: '+error)) }); }) } async JucunduNextItem(sale_id, timestamp, item_id, num_lot, title, description, EstimateLow, EstimateHigh, RawData){ console.log('JucunduNextItem', sale_id, timestamp, item_id, num_lot) return new Promise((resolve, reject) => { fetch(this._JucundusUrl+'/api/lot/NextItem', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify( { idPlatform: item_id, idSalePlatform: sale_id, platform: this._Name, timestamp: timestamp, lotNumber: num_lot, title: title, description: description, EstimateLow: EstimateLow, EstimateHigh: EstimateHigh, RawData: RawData } )}) .then(resolve(true)) .catch(error => { console.error(error); reject(new Error('Error: '+error)) }); }) } async JucundusBid(item_id, timestamp, amount, auctioned_type){ console.log('JucundusBid', timestamp, item_id, amount, auctioned_type) return new Promise((resolve, reject) => { fetch(this._JucundusUrl+'/api/lot/Bid', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify( { idPlatform: item_id, platform: this._Name, timestamp: timestamp, amount: amount, auctioned_type: auctioned_type } )}) .then(resolve(true)) .catch(error => { console.error(error); reject(new Error('Error: '+error)) }); }) } async JucunduAuctionedItem(item_id, timestamp, amount, sold, auctioned_type){ console.log('JucunduAuctionedItem', timestamp, item_id, amount, sold) return new Promise((resolve, reject) => { fetch(this._JucundusUrl+'/api/lot/AuctionedItem', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify( { idPlatform: item_id, platform: this._Name, timestamp: timestamp, amount: amount, auctioned_type: auctioned_type, sold: sold, } )}) .then(resolve(true)) .catch(error => { console.error(error); reject(new Error('Error: '+error)) }); }) } }; class ScraperTools { _CONST_INTERENCHERES = 'interencheres' _CONST_DROUOT = 'drouot' detectPlatform(URL){ let Url = 'http'+String(URL).split("http")[1] if(Url.includes('interencheres')){ return this._CONST_INTERENCHERES } if(Url.includes('drouot')){ return this._CONST_DROUOT } } async clickLink(XPath = [], page, context){ for (let XPathString of XPath) { try{ await page.waitForXPath(XPathString, { timeout: 1000 }); }catch(e){} let Elements = await page.$x(XPathString); if (Elements.length > 0) { await Elements[0].evaluate(b => b.click()); return true; } } console.error("Error: No Link found for "+context) return false; } async getAttribute(XPath = [], page, attribute, context){ for (let XPathString of XPath) { try{ await page.waitForXPath(XPathString, { timeout: 1000 }); }catch(e){} let Elements = await page.$x(XPathString); if (Elements.length > 0) { const Attribute = await page.evaluate((element,attribute) => element.getAttribute(attribute), Elements[0],attribute); if(Attribute != "" && Attribute != null && Attribute != undefined) { return Attribute; } } } console.error("Error: No content found for the Attribute "+attribute+" for "+context) return ""; } async getTextContent(XPath = [], page, context, log = false){ for (let XPathString of XPath) { try{ await page.waitForXPath(XPathString, { timeout: 1000 }); }catch(e){} let Elements = await page.$x(XPathString); if (Elements.length > 0) { if(log) console.log(Elements) let Content = await page.evaluate(el => el.textContent, Elements[0]); if(Content != "" && Content != null && Content != undefined) { return Content; } } } console.error("Error: No content found for "+context) return ""; } async ElementExists(XPath = [], page, context){ for (let XPathString of XPath) { try{ let Elements = await page.$x(XPathString); if (Elements.length > 0) { return true; } }catch(e){} } return false; } async getTextContentElement(XPath = [], page, Element, context){ for (let XPathString of XPath) { let El = await Element.$x(XPathString); if (El.length > 0) { let Content = await page.evaluate(el => el.textContent, El[0]); if(Content != "" && Content != null && Content != undefined) { return Content; } } } console.error("Error: No content found for "+context) return ""; } async getAttributeElement(XPath = [], page, Element, attribute, context){ for (let XPathString of XPath) { let El = await Element.$x(XPathString); if (El.length > 0) { const Attribute = await page.evaluate((el, attr) => el.getAttribute(attr), El[0], attribute); if(Attribute != "" && Attribute != null && Attribute != undefined) { return Attribute; } } } console.error("Error: No content found for the Attribute "+attribute+" for "+context) return ""; } } module.exports = {Scraper, ScraperTools};