- Per generare la sinossi è possibile estrarre con 1 click la descrizione sia da Amazon che da GruppoMacro.
- corretto piccolo bug sul catalogo.
This commit is contained in:
99
src/server/models/myscrapingbook.js
Executable file
99
src/server/models/myscrapingbook.js
Executable file
@@ -0,0 +1,99 @@
|
|||||||
|
const mongoose = require('mongoose').set('debug', false);
|
||||||
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const tools = require('../tools/general');
|
||||||
|
|
||||||
|
mongoose.Promise = global.Promise;
|
||||||
|
mongoose.level = 'F';
|
||||||
|
|
||||||
|
// Resolving error Unknown modifier: $pushAll
|
||||||
|
mongoose.plugin((schema) => {
|
||||||
|
schema.options.usePushEach = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const MyScrapingBookSchema = new Schema({
|
||||||
|
isbn: {
|
||||||
|
type: String,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
isbn10: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
fonte: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
titolo: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
titoloOriginale: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
sottotitolo: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
autore: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
pagine: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
misure: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
edizione: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
editore: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
date_pub: {
|
||||||
|
type: Date,
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
stelline: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
prezzo: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
date_extraction: {
|
||||||
|
type: Date,
|
||||||
|
},
|
||||||
|
descrizione_lunga: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
MyScrapingBookSchema.statics.getFieldsForSearch = function () {
|
||||||
|
return [{ field: 'titolo', type: tools.FieldType.string }];
|
||||||
|
};
|
||||||
|
|
||||||
|
MyScrapingBookSchema.statics.executeQueryTable = function (idapp, params, user) {
|
||||||
|
params.fieldsearch = this.getFieldsForSearch();
|
||||||
|
return tools.executeQueryTable(this, idapp, params, user);
|
||||||
|
};
|
||||||
|
|
||||||
|
MyScrapingBookSchema.statics.findAllIdApp = async function (idapp) {
|
||||||
|
const MyScrapingBook = this;
|
||||||
|
|
||||||
|
const myfind = { idapp };
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await MyScrapingBook.find(myfind).sort({ titolo: 1 }).lean();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Errore in MyScrapingBook:', err, model);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const MyScrapingBook = mongoose.model('MyScrapingBook', MyScrapingBookSchema);
|
||||||
|
|
||||||
|
MyScrapingBook.createIndexes()
|
||||||
|
.then(() => {})
|
||||||
|
.catch((err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = { MyScrapingBook };
|
||||||
@@ -494,7 +494,7 @@ module.exports.findAllIdApp = async function (idapp, code, id, all, isbn) {
|
|||||||
myfind = { ...myfind, code };
|
myfind = { ...myfind, code };
|
||||||
}
|
}
|
||||||
if (isbn) {
|
if (isbn) {
|
||||||
myfind = { ...myfind, sbn };
|
myfind = { ...myfind, isbn };
|
||||||
}
|
}
|
||||||
if (id) {
|
if (id) {
|
||||||
myqueryadd = {
|
myqueryadd = {
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ class CronMod {
|
|||||||
// } else if (mydata.dbop === 'rigeneraTutto') {
|
// } else if (mydata.dbop === 'rigeneraTutto') {
|
||||||
// await ListaIngresso.Esegui_CronTab(idapp, mydata);
|
// await ListaIngresso.Esegui_CronTab(idapp, mydata);
|
||||||
} else if (mydata.dbop === "ScraperMultipleDataAmazon") {
|
} else if (mydata.dbop === "ScraperMultipleDataAmazon") {
|
||||||
mystr = await AmazonBookScraper.ScraperMultipleDataAmazon(idapp, mydata.options);
|
mystr = await AmazonBookScraper.ScraperMultipleDataAmazon(idapp, {update: true, aggiornasoloSeVuoti: true, forzaricarica: false});
|
||||||
|
ris = { mystr };
|
||||||
|
} else if (mydata.dbop === "ScraperMultipleDataDBStored") {
|
||||||
|
mystr = await AmazonBookScraper.ScraperMultipleDataDBStored(idapp, {update: true, aggiornasoloSeVuoti: true, forzaricarica: false, dbstored: true});
|
||||||
ris = { mystr };
|
ris = { mystr };
|
||||||
} else if (mydata.dbop === "ScraperGeneraCSV") {
|
} else if (mydata.dbop === "ScraperGeneraCSV") {
|
||||||
mystr = await AmazonBookScraper.ScraperGeneraCSV(idapp, mydata.options, res);
|
mystr = await AmazonBookScraper.ScraperGeneraCSV(idapp, mydata.options, res);
|
||||||
|
|||||||
@@ -9,32 +9,76 @@ const shared_consts = require('../tools/shared_nodejs');
|
|||||||
|
|
||||||
const fs = require('fs').promises; // 👈 Usa il modulo promises
|
const fs = require('fs').promises; // 👈 Usa il modulo promises
|
||||||
|
|
||||||
|
const { MyScrapingBook } = require('../models/myscrapingbook');
|
||||||
|
|
||||||
class AmazonBookScraper {
|
class AmazonBookScraper {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.baseUrl = 'https://www.amazon.it/dp/';
|
this.baseUrl = 'https://www.amazon.it/dp/';
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchPageISBN10(isbn10) {
|
getUserAgentRandom() {
|
||||||
|
// Lista di User-Agent comuni per i vari browser
|
||||||
|
const userAgents = [
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/91.0.864.59 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0',
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0',
|
||||||
|
'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; AS; rv:11.0) like Gecko',
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 6.1; rv:56.0) Gecko/20100101 Firefox/56.0',
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Seleziona un User-Agent casuale dalla lista
|
||||||
|
const randomIndex = Math.floor(Math.random() * userAgents.length);
|
||||||
|
return userAgents[randomIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchPageISBN10(isbn10, isbn) {
|
||||||
|
if (!isbn10) return false;
|
||||||
|
|
||||||
const url = `${this.baseUrl}${isbn10}`;
|
const url = `${this.baseUrl}${isbn10}`;
|
||||||
try {
|
const retryLimit = 2; // Numero massimo di tentativi
|
||||||
const { data } = await axios.get(url, {
|
const timeout = 7000; // Timeout di 5 secondi per la richiesta
|
||||||
headers: {
|
const delay = 10000; // Ritardo tra i tentativi (10 secondi)
|
||||||
'User-Agent':
|
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' +
|
for (let attempt = 1; attempt <= retryLimit; attempt++) {
|
||||||
'AppleWebKit/537.36 (KHTML, like Gecko) ' +
|
try {
|
||||||
'Chrome/113.0.0.0 Safari/537.36',
|
const { data } = await axios.get(url, {
|
||||||
// altri header se necessario
|
headers: {
|
||||||
},
|
'User-Agent': this.getUserAgentRandom(),
|
||||||
});
|
// Aggiungi altri header se necessario
|
||||||
return { html: data, url };
|
},
|
||||||
} catch (err) {
|
timeout, // Timeout di 5 secondi per la richiesta
|
||||||
console.error(`Errore fetching ISBN ${isbn10}:`, err.message);
|
});
|
||||||
return null;
|
return { html: data, url };
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Errore fetching isbn10 ${isbn10} (ISBN:${isbn}) (tentativo ${attempt}):`, err.message);
|
||||||
|
|
||||||
|
if (attempt < retryLimit) {
|
||||||
|
console.log(`Riprovo tra ${delay / 1000} secondi...`);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, delay)); // Ritardo prima di riprovare
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
`Impossibile recuperare la pagina per ISBN10 ${isbn10} (ISBN:${isbn}) dopo ${retryLimit} tentativi.`
|
||||||
|
);
|
||||||
|
await Product.findOneAndUpdate(
|
||||||
|
{ isbn: isbn },
|
||||||
|
{ $set: { scraped: true, scraped_error: true } },
|
||||||
|
{ upsert: true, new: true, includeResultMetadata: true }
|
||||||
|
).lean();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isbn13to10(isbn13) {
|
isbn13to10(isbn13) {
|
||||||
try {
|
try {
|
||||||
if (!isbn13.startsWith('978') || isbn13.length !== 13) return null;
|
if (!(isbn13.startsWith('978') || isbn13.startsWith('979')) || isbn13.length !== 13) return null;
|
||||||
|
|
||||||
const core = isbn13.slice(3, 12); // i 9 numeri centrali
|
const core = isbn13.slice(3, 12); // i 9 numeri centrali
|
||||||
|
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
@@ -60,7 +104,7 @@ class AmazonBookScraper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async extractData(myproduct, html, url) {
|
async extractData(myproduct, html, url, isbn10) {
|
||||||
const $ = cheerio.load(html);
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
const productInfo = await ProductInfo.findOne({ _id: myproduct.idProductInfo }).lean();
|
const productInfo = await ProductInfo.findOne({ _id: myproduct.idProductInfo }).lean();
|
||||||
@@ -94,11 +138,19 @@ class AmazonBookScraper {
|
|||||||
let edizione = null;
|
let edizione = null;
|
||||||
let publisher = null;
|
let publisher = null;
|
||||||
let data_pubblicazione = null;
|
let data_pubblicazione = null;
|
||||||
|
let descrizione_lunga = null;
|
||||||
|
let prezzo = null;
|
||||||
|
let stelline = null;
|
||||||
|
let autore = null;
|
||||||
|
|
||||||
numpagine = this.extractNumeroDiPagine($);
|
numpagine = this.extractNumeroDiPagine($);
|
||||||
const dim = this.extractDimensions($);
|
const dim = this.extractDimensions($);
|
||||||
misure = this.convertDimensionsToMisureMacro(dim);
|
misure = this.convertDimensionsToMisureMacro(dim);
|
||||||
const data_pubb = this.extractDataPubblicazione($);
|
const data_pubb = this.extractDataPubblicazione($);
|
||||||
|
descrizione_lunga = this.extractDescrizioneLunga($);
|
||||||
|
autore = this.extractAutore($);
|
||||||
|
stelline = this.extractStelline($);
|
||||||
|
prezzo = this.extractPrezzo($);
|
||||||
data_pubblicazione = this.parseItalianDate(data_pubb);
|
data_pubblicazione = this.parseItalianDate(data_pubb);
|
||||||
|
|
||||||
publisher = this.extractEditore($);
|
publisher = this.extractEditore($);
|
||||||
@@ -107,39 +159,121 @@ class AmazonBookScraper {
|
|||||||
edizione = this.extractMonthYear(data_pubb);
|
edizione = this.extractMonthYear(data_pubb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const fonte = 'AMAZON';
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
isbn: myproduct.isbn,
|
||||||
|
isbn10,
|
||||||
titolo: title,
|
titolo: title,
|
||||||
|
fonte,
|
||||||
...(titoloOriginale ? { titoloOriginale } : {}),
|
...(titoloOriginale ? { titoloOriginale } : {}),
|
||||||
...(sottotitolo ? { sottotitolo } : { sottotitolo: '' }),
|
...(sottotitolo ? { sottotitolo } : { sottotitolo: '' }),
|
||||||
|
...(autore ? { autore } : { autore: '' }),
|
||||||
|
...(stelline ? { stelline } : {}),
|
||||||
...(numpagine ? { numpagine } : {}),
|
...(numpagine ? { numpagine } : {}),
|
||||||
...(misure ? { misure } : {}),
|
...(misure ? { misure } : {}),
|
||||||
...(edizione ? { edizione } : {}),
|
...(edizione ? { edizione } : {}),
|
||||||
...(data_pubblicazione ? { data_pubblicazione } : {}),
|
...(descrizione_lunga ? { descrizione_lunga } : {}),
|
||||||
...(publisher ? { editore: publisher } : {}),
|
...(publisher ? { editore: publisher } : {}),
|
||||||
url: `<a href="${url}" target="_blank">URL</a>`,
|
url: `<a href="${url}" target="_blank">VAI AL SITO ${fonte}</a>`,
|
||||||
|
...(data_pubblicazione ? { data_pubblicazione } : {}),
|
||||||
|
...(prezzo ? { prezzo } : {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Aggiungilo al record
|
||||||
|
await this.addOrUpdateMyScrapingBook(data);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findRecordMyScrapingBookByIsbn(isbn) {
|
||||||
|
const record = await MyScrapingBook.findOne({ isbn }).lean();
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addOrUpdateMyScrapingBook(data) {
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
isbn,
|
||||||
|
isbn10,
|
||||||
|
titolo,
|
||||||
|
titoloOriginale,
|
||||||
|
fonte,
|
||||||
|
url,
|
||||||
|
sottotitolo,
|
||||||
|
autore,
|
||||||
|
numpagine,
|
||||||
|
misure,
|
||||||
|
edizione,
|
||||||
|
editore,
|
||||||
|
data_pubblicazione,
|
||||||
|
stelline,
|
||||||
|
prezzo,
|
||||||
|
descrizione_lunga,
|
||||||
|
} = data;
|
||||||
|
|
||||||
|
// Cerca un record esistente per ISBN
|
||||||
|
let record = await MyScrapingBook.findOne({ isbn }).lean();
|
||||||
|
|
||||||
|
// Se il record esiste, aggiorna i campi
|
||||||
|
await MyScrapingBook.updateOne(
|
||||||
|
{ isbn },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
isbn10,
|
||||||
|
titolo,
|
||||||
|
fonte,
|
||||||
|
titoloOriginale,
|
||||||
|
sottotitolo,
|
||||||
|
autore,
|
||||||
|
pagine: numpagine,
|
||||||
|
misure,
|
||||||
|
edizione,
|
||||||
|
editore,
|
||||||
|
date_pub: data_pubblicazione,
|
||||||
|
url,
|
||||||
|
stelline,
|
||||||
|
prezzo,
|
||||||
|
descrizione_lunga,
|
||||||
|
date_extraction: new Date(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ upsert: true }
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Errore gestendo MyScrapingBook:', err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async scrapeISBN(myproduct, isbn, options) {
|
async scrapeISBN(myproduct, isbn, options) {
|
||||||
try {
|
try {
|
||||||
const isbn10 = this.isbn13to10(isbn);
|
const datastored = await this.findRecordMyScrapingBookByIsbn(isbn);
|
||||||
const res = await this.fetchPageISBN10(isbn10);
|
|
||||||
if (!res) {
|
|
||||||
await Product.findOneAndUpdate(
|
|
||||||
{ _id: myproduct._id },
|
|
||||||
{ $set: { scraped: true, scraped_error: true } },
|
|
||||||
{ upsert: true, new: true, includeResultMetadata: true }
|
|
||||||
).lean();
|
|
||||||
|
|
||||||
return null;
|
let data = null;
|
||||||
}
|
|
||||||
const html = res.html;
|
|
||||||
if (!html) return null;
|
|
||||||
|
|
||||||
let updated = null;
|
let updated = null;
|
||||||
let risupdate = null;
|
let risupdate = null;
|
||||||
|
|
||||||
const data = await this.extractData(myproduct, html, res.url);
|
// prima cerca sulla tabella che ho scaricato
|
||||||
|
if (options.forzaricarica || !datastored) {
|
||||||
|
const isbn10 = this.isbn13to10(isbn);
|
||||||
|
const res = await this.fetchPageISBN10(isbn10, isbn);
|
||||||
|
if (!res) {
|
||||||
|
await Product.findOneAndUpdate(
|
||||||
|
{ _id: myproduct._id },
|
||||||
|
{ $set: { scraped: true, scraped_error: true } },
|
||||||
|
{ upsert: true, new: true, includeResultMetadata: true }
|
||||||
|
).lean();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const html = res.html;
|
||||||
|
if (!html) return null;
|
||||||
|
|
||||||
|
data = await this.extractData(myproduct, html, res.url, isbn10);
|
||||||
|
} else {
|
||||||
|
data = { ...datastored };
|
||||||
|
}
|
||||||
|
|
||||||
if (!options?.update) return data;
|
if (!options?.update) return data;
|
||||||
|
|
||||||
@@ -233,7 +367,7 @@ class AmazonBookScraper {
|
|||||||
{ $set: { scraped: true, scraped_date: new Date() } },
|
{ $set: { scraped: true, scraped_date: new Date() } },
|
||||||
{ upsert: true, new: true, returnDocument: 'after' }
|
{ upsert: true, new: true, returnDocument: 'after' }
|
||||||
);
|
);
|
||||||
console.log('upd', upd);
|
// console.log('upd', upd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aggiornaProductInfo) {
|
if (aggiornaProductInfo) {
|
||||||
@@ -293,13 +427,15 @@ class AmazonBookScraper {
|
|||||||
if (!arrvar.misure) {
|
if (!arrvar.misure) {
|
||||||
datimancanti = true;
|
datimancanti = true;
|
||||||
}
|
}
|
||||||
if (!arrvar.edizione) {
|
/*if (!arrvar.edizione) {
|
||||||
datimancanti = true;
|
datimancanti = true;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (product.idProductInfo) {
|
if (product.idProductInfo) {
|
||||||
if (!tools.isDateValid(product.idProductInfo.date_pub)) datimancanti = true;
|
if (!tools.isDateValid(product.idProductInfo.date_pub)) {
|
||||||
|
datimancanti = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return datimancanti;
|
return datimancanti;
|
||||||
@@ -333,7 +469,7 @@ class AmazonBookScraper {
|
|||||||
console.log(`scrapeMultiple INIZIATO...`);
|
console.log(`scrapeMultiple INIZIATO...`);
|
||||||
let dataorainizio = new Date();
|
let dataorainizio = new Date();
|
||||||
|
|
||||||
for (let i = 0; i < 100 && i < products.length; i++) {
|
for (let i = 0; i < products.length; i++) {
|
||||||
const product = products[i];
|
const product = products[i];
|
||||||
let isbn = product.isbn;
|
let isbn = product.isbn;
|
||||||
|
|
||||||
@@ -348,7 +484,7 @@ class AmazonBookScraper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i % 1 === 0) {
|
if (i % 1 === 0) {
|
||||||
const percentuale = ((quanti / products.length) * 100).toFixed(2);
|
const percentuale = ((i / products.length) * 100).toFixed(2);
|
||||||
console.log(
|
console.log(
|
||||||
`Scraping: ${product.isbn} - ${product.idProductInfo.name} - ${quanti} su ${i + 1} / ${
|
`Scraping: ${product.isbn} - ${product.idProductInfo.name} - ${quanti} su ${i + 1} / ${
|
||||||
products.length
|
products.length
|
||||||
@@ -357,10 +493,11 @@ class AmazonBookScraper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Per evitare blocchi, metti una pausa (es. 2 secondi)
|
// Per evitare blocchi, metti una pausa (es. 2 secondi)
|
||||||
await new Promise((r) => setTimeout(r, 3000));
|
await new Promise((r) => setTimeout(r, 2000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mylog += `RECORD AGGIORNATI: ${results.length - 1} su ${quanti}`;
|
mylog += `RECORD AGGIORNATI: ${results.length - 1} su ${quanti}`;
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
@@ -389,6 +526,12 @@ class AmazonBookScraper {
|
|||||||
await Product.updateMany({ idapp, scraped_updated: true }, { $set: { scraped_updated: false } });
|
await Product.updateMany({ idapp, scraped_updated: true }, { $set: { scraped_updated: false } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async ScraperAzzeraFlagErrori(idapp, options) {
|
||||||
|
// aggiorna tutti i record di Product (con idapp) scraped: false
|
||||||
|
|
||||||
|
await Product.updateMany({ idapp, scraped_error: true }, { $set: { scraped: false } });
|
||||||
|
}
|
||||||
|
|
||||||
static async removeDuplicateVariations(idapp, options) {
|
static async removeDuplicateVariations(idapp, options) {
|
||||||
let mylog = 'removeDuplicateVariations...\n';
|
let mylog = 'removeDuplicateVariations...\n';
|
||||||
|
|
||||||
@@ -478,7 +621,6 @@ class AmazonBookScraper {
|
|||||||
.populate({ path: 'idProductInfo', select: 'date_pub name sottotitolo' })
|
.populate({ path: 'idProductInfo', select: 'date_pub name sottotitolo' })
|
||||||
.lean();
|
.lean();
|
||||||
|
|
||||||
|
|
||||||
// Funzione per "appiattire" i dati
|
// Funzione per "appiattire" i dati
|
||||||
const flattenData = (data) => {
|
const flattenData = (data) => {
|
||||||
return data.map((item) => {
|
return data.map((item) => {
|
||||||
@@ -565,8 +707,9 @@ class AmazonBookScraper {
|
|||||||
idapp,
|
idapp,
|
||||||
isbn: { $exists: true, $ne: '' },
|
isbn: { $exists: true, $ne: '' },
|
||||||
scraped: { $ne: true }, // Escludi direttamente i record con scraped = true
|
scraped: { $ne: true }, // Escludi direttamente i record con scraped = true
|
||||||
$or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
|
|
||||||
$or: [{ scraped_error: { $exists: false } }, { scraped_error: { $exists: true, $eq: false } }],
|
$or: [{ scraped_error: { $exists: false } }, { scraped_error: { $exists: true, $eq: false } }],
|
||||||
|
/*$or: [{ deleted: { $exists: false } }, { deleted: { $exists: true, $eq: false } }],
|
||||||
|
*/
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Popoliamo il campo idProductInfo
|
// Popoliamo il campo idProductInfo
|
||||||
@@ -622,31 +765,131 @@ class AmazonBookScraper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extractDataPubblicazione($) {
|
extractDataPubblicazione($) {
|
||||||
// Seleziona il div con id specifico per la data di pubblicazione
|
try {
|
||||||
const publicationDate = $('#rpi-attribute-book_details-publication_date .rpi-attribute-value span').text().trim();
|
// Seleziona il div con id specifico per la data di pubblicazione
|
||||||
|
const publicationDate = $('#rpi-attribute-book_details-publication_date .rpi-attribute-value span').text().trim();
|
||||||
|
|
||||||
// Se non trova la data, ritorna null
|
// Se non trova la data, ritorna null
|
||||||
return publicationDate || null;
|
return publicationDate || null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error extracting publication date:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extractDescrizioneLunga($) {
|
||||||
|
try {
|
||||||
|
// Cerca l'elemento che contiene la descrizione lunga
|
||||||
|
const descriptionElement = $('#bookDescription_feature_div .a-expander-content span');
|
||||||
|
|
||||||
|
// Estrai il testo e rimuovi eventuali spazi extra o tag HTML
|
||||||
|
const description = descriptionElement.text().trim();
|
||||||
|
|
||||||
|
// Se la descrizione è vuota, restituisci null
|
||||||
|
return description || null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error extracting long description:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extractAutore($) {
|
||||||
|
try {
|
||||||
|
// Seleziona tutti gli elementi che contengono gli autori
|
||||||
|
const authorsElements = $('#bylineInfo .author a');
|
||||||
|
|
||||||
|
// Estrai il testo per ogni autore e rimuovi spazi extra
|
||||||
|
const authors = authorsElements.map((i, el) => $(el).text().trim()).get();
|
||||||
|
|
||||||
|
// Se ci sono autori, restituiscili come stringa separata da virgole
|
||||||
|
return authors.length > 0 ? authors.join(', ') : null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error extracting authors:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extractStelline($) {
|
||||||
|
try {
|
||||||
|
// Cerca l'elemento che contiene la descrizione lunga
|
||||||
|
// Seleziona l'elemento che contiene il voto medio (5,0 su 5 stelle)
|
||||||
|
const ratingText = $('#acrPopover').attr('title');
|
||||||
|
|
||||||
|
if (ratingText) {
|
||||||
|
// Estrai il numero di stelle dal testo "5,0 su 5 stelle"
|
||||||
|
const stars = ratingText.split(' su ')[0].replace(',', '.'); // Cambia la virgola in punto
|
||||||
|
return stars; // Restituisce il numero di stelle
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error extracting stars:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extractPrezzo($) {
|
||||||
|
try {
|
||||||
|
// Seleziona l'elemento che contiene il prezzo
|
||||||
|
const priceElement = $(
|
||||||
|
'.a-box-group .a-section #desktop_qualifiedBuyBox #corePriceDisplay_desktop_feature_div .a-price .a-price-whole'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Estrai il prezzo principale e la parte decimale
|
||||||
|
const wholePrice = priceElement.text().trim();
|
||||||
|
const decimalPrice = $(
|
||||||
|
'.a-box-group .a-section #desktop_qualifiedBuyBox #corePriceDisplay_desktop_feature_div .a-price .a-price-fraction'
|
||||||
|
)
|
||||||
|
.text()
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
// Estrai il simbolo della valuta
|
||||||
|
const currencySymbol = $(
|
||||||
|
'.a-box-group .a-section #desktop_qualifiedBuyBox #corePriceDisplay_desktop_feature_div .a-price .a-price-symbol'
|
||||||
|
)
|
||||||
|
.text()
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
// Se il prezzo è stato trovato, formattalo come prezzo completo
|
||||||
|
if (wholePrice && decimalPrice && currencySymbol) {
|
||||||
|
const fullPrice = `${wholePrice}${decimalPrice} ${currencySymbol}`;
|
||||||
|
return fullPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se non trova il prezzo, restituisce null
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error extracting price:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extractNumeroDiPagine($) {
|
extractNumeroDiPagine($) {
|
||||||
// Seleziona il div con id specifico per pagine
|
try {
|
||||||
const pagesText = $('#rpi-attribute-book_details-fiona_pages .rpi-attribute-value span').text().trim();
|
// Seleziona il div con id specifico per pagine
|
||||||
|
const pagesText = $('#rpi-attribute-book_details-fiona_pages .rpi-attribute-value span').text().trim();
|
||||||
|
|
||||||
// pagesText dovrebbe essere tipo "184 pagine"
|
// pagesText dovrebbe essere tipo "184 pagine"
|
||||||
if (!pagesText) return null;
|
if (!pagesText) return null;
|
||||||
|
|
||||||
// Estrai solo il numero (facoltativo)
|
// Estrai solo il numero (facoltativo)
|
||||||
const match = pagesText.match(/(\d+)/);
|
const match = pagesText.match(/(\d+)/);
|
||||||
return match ? match[1] : pagesText; // ritorna solo il numero o il testo intero
|
return match ? match[1] : pagesText; // ritorna solo il numero o il testo intero
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error extracting number of pages:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extractDimensions($) {
|
extractDimensions($) {
|
||||||
// Seleziona il div con id specifico per dimensioni
|
try {
|
||||||
const dimText = $('#rpi-attribute-book_details-dimensions .rpi-attribute-value span').text().trim();
|
// Seleziona il div con id specifico per dimensioni
|
||||||
|
const dimText = $('#rpi-attribute-book_details-dimensions .rpi-attribute-value span').text().trim();
|
||||||
|
|
||||||
// Se non trova niente ritorna null
|
// Se non trova niente ritorna null
|
||||||
return dimText || null;
|
return dimText || null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error extracting dimensions:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
convertDimensionsToMisureMacro(dimString) {
|
convertDimensionsToMisureMacro(dimString) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const Gasordine = require('../models/gasordine');
|
|||||||
|
|
||||||
const { User } = require('../models/user');
|
const { User } = require('../models/user');
|
||||||
|
|
||||||
const AmazonBookScraper = require('../modules/scraping');
|
const AmazonBookScraper = require('../modules/Scraping');
|
||||||
|
|
||||||
const { Catalog } = require('../models/catalog');
|
const { Catalog } = require('../models/catalog');
|
||||||
const { RaccoltaCataloghi } = require('../models/raccoltacataloghi');
|
const { RaccoltaCataloghi } = require('../models/raccoltacataloghi');
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ router.post('/', auth_default, async function (req, res, next) {
|
|||||||
|
|
||||||
let ismanager = await tools.isManagerByReq(req);
|
let ismanager = await tools.isManagerByReq(req);
|
||||||
|
|
||||||
let catalogs = await Catalog.findAllIdApp(idapp, '', undefined, ismanager);
|
let catalogs = await Catalog.findAllIdApp(idapp);
|
||||||
let orders = null;
|
let orders = null;
|
||||||
|
|
||||||
if (catalogs) return res.send({ code: server_constants.RIS_CODE_OK, catalogs, orders });
|
if (catalogs) return res.send({ code: server_constants.RIS_CODE_OK, catalogs, orders });
|
||||||
|
|||||||
57
src/server/router/myscraping_router.js
Executable file
57
src/server/router/myscraping_router.js
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
const tools = require('../tools/general');
|
||||||
|
|
||||||
|
var server_constants = require('../tools/server_constants');
|
||||||
|
|
||||||
|
const { User } = require('../models/user');
|
||||||
|
|
||||||
|
var { authenticate, auth_default } = require('../middleware/authenticate');
|
||||||
|
|
||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
|
const { MyScrapingBook } = require('../models/myscrapingbook');
|
||||||
|
const Product = require('../models/product');
|
||||||
|
|
||||||
|
const AmazonBookScraper = require('../modules/Scraping');
|
||||||
|
|
||||||
|
//GET /products
|
||||||
|
router.post('/', auth_default, async function (req, res, next) {
|
||||||
|
const idapp = req.body.idapp;
|
||||||
|
const isbn = req.body.isbn;
|
||||||
|
const forzacaricamento = req.body.forzacaricamento;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let myscraping = null;
|
||||||
|
if (isbn) {
|
||||||
|
myscraping = await MyScrapingBook.findOne({ isbn }).lean();
|
||||||
|
|
||||||
|
if (!myscraping && forzacaricamento) {
|
||||||
|
const scraper = new AmazonBookScraper();
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
update: false,
|
||||||
|
forzaricarica: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const myproduct = await Product.getProductByIsbn(idapp, isbn);
|
||||||
|
if (myproduct && myproduct.length > 0) {
|
||||||
|
myscraping = await scraper.scrapeISBN(myproduct[0], isbn, options);
|
||||||
|
// console.log(myscraping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myscraping) {
|
||||||
|
return res.send({ code: server_constants.RIS_CODE_OK, myscraping });
|
||||||
|
} else {
|
||||||
|
return res.send({ code: server_constants.RIS_CODE_OK, myscraping: null });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: e.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -128,6 +128,7 @@ connectToDatabase(connectionUrl, options)
|
|||||||
const site_router = require('./router/site_router');
|
const site_router = require('./router/site_router');
|
||||||
const admin_router = require('./router/admin_router');
|
const admin_router = require('./router/admin_router');
|
||||||
const products_router = require('./router/products_router');
|
const products_router = require('./router/products_router');
|
||||||
|
const myscraping_router = require('./router/myscraping_router');
|
||||||
const catalogs_router = require('./router/catalogs_router');
|
const catalogs_router = require('./router/catalogs_router');
|
||||||
const cart_router = require('./router/cart_router');
|
const cart_router = require('./router/cart_router');
|
||||||
const orders_router = require('./router/orders_router');
|
const orders_router = require('./router/orders_router');
|
||||||
@@ -238,6 +239,7 @@ connectToDatabase(connectionUrl, options)
|
|||||||
app.use('/site', site_router);
|
app.use('/site', site_router);
|
||||||
app.use('/admin', admin_router);
|
app.use('/admin', admin_router);
|
||||||
app.use('/products', products_router);
|
app.use('/products', products_router);
|
||||||
|
app.use('/myscraping', myscraping_router);
|
||||||
app.use('/catalogs', catalogs_router);
|
app.use('/catalogs', catalogs_router);
|
||||||
app.use('/cart', cart_router);
|
app.use('/cart', cart_router);
|
||||||
app.use('/orders', orders_router);
|
app.use('/orders', orders_router);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ const Pickup = require('../models/pickup');
|
|||||||
const { Newstosent } = require('../models/newstosent');
|
const { Newstosent } = require('../models/newstosent');
|
||||||
const { MyPage } = require('../models/mypage');
|
const { MyPage } = require('../models/mypage');
|
||||||
const { MyElem } = require('../models/myelem');
|
const { MyElem } = require('../models/myelem');
|
||||||
|
const { MyScrapingBook } = require('../models/myscrapingbook');
|
||||||
const { Cron } = require('../models/cron');
|
const { Cron } = require('../models/cron');
|
||||||
const { MyScheda } = require('../models/myscheda');
|
const { MyScheda } = require('../models/myscheda');
|
||||||
const { MyBot } = require('../models/bot');
|
const { MyBot } = require('../models/bot');
|
||||||
@@ -200,6 +201,8 @@ module.exports = {
|
|||||||
mytable = MyPage;
|
mytable = MyPage;
|
||||||
else if (tablename === 'myelems')
|
else if (tablename === 'myelems')
|
||||||
mytable = MyElem;
|
mytable = MyElem;
|
||||||
|
else if (tablename === 'myscrapingbooks')
|
||||||
|
mytable = MyScrapingBook;
|
||||||
else if (tablename === 'crons')
|
else if (tablename === 'crons')
|
||||||
mytable = Cron;
|
mytable = Cron;
|
||||||
else if (tablename === 'myschedas')
|
else if (tablename === 'myschedas')
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.2.47
|
1.2.48
|
||||||
Reference in New Issue
Block a user