- ver 1.2.47 :
- corretto errore di modifica scheda - aggiunto scraping (fase 1)
This commit is contained in:
@@ -56,6 +56,9 @@ const MyPageSchema = new Schema({
|
|||||||
only_residenti: {
|
only_residenti: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
},
|
||||||
|
only_admin: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
color: {
|
color: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
@@ -200,6 +203,7 @@ MyPageSchema.statics.findOnlyStruttRec = async function (idapp) {
|
|||||||
active: 1,
|
active: 1,
|
||||||
onlyif_logged: 1,
|
onlyif_logged: 1,
|
||||||
only_residenti: 1,
|
only_residenti: 1,
|
||||||
|
only_admin: 1,
|
||||||
inmenu: 1,
|
inmenu: 1,
|
||||||
submenu: 1,
|
submenu: 1,
|
||||||
iconsize: 1,
|
iconsize: 1,
|
||||||
@@ -227,6 +231,7 @@ MyPageSchema.statics.findInternalPages = async function (idapp) {
|
|||||||
path: 1,
|
path: 1,
|
||||||
onlyif_logged: 1,
|
onlyif_logged: 1,
|
||||||
only_residenti: 1,
|
only_residenti: 1,
|
||||||
|
only_admin: 1,
|
||||||
}).lean();
|
}).lean();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ const productSchema = new Schema({
|
|||||||
idapp: {
|
idapp: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
|
delete: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
active: {
|
active: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
@@ -462,7 +465,10 @@ module.exports.findAllIdApp = async function (idapp, code, id, all) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (idapp) {
|
if (idapp) {
|
||||||
myfind = { idapp };
|
myfind = {
|
||||||
|
idapp,
|
||||||
|
$or: [{ delete: { $exists: false } }, { delete: false }],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!all) {
|
if (!all) {
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ const productInfoSchema = new Schema({
|
|||||||
idapp: {
|
idapp: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
|
delete: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
department: {
|
department: {
|
||||||
type: String, ref: 'Department'
|
type: String, ref: 'Department'
|
||||||
},
|
},
|
||||||
@@ -206,7 +209,13 @@ module.exports.findAllIdApp = async function (idapp, code, id) {
|
|||||||
try {
|
try {
|
||||||
|
|
||||||
if (idapp)
|
if (idapp)
|
||||||
myfind = { idapp };
|
myfind = {
|
||||||
|
idapp,
|
||||||
|
$or: [
|
||||||
|
{ delete: { $exists: false } },
|
||||||
|
{ delete: false }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
if (code) {
|
if (code) {
|
||||||
myfind = { ...myfind, code }
|
myfind = { ...myfind, code }
|
||||||
@@ -539,11 +548,17 @@ module.exports.removeProductInfoWithoutDateUpdatedFromGM = async function (idapp
|
|||||||
for (const productinfo of arrproductInfo) {
|
for (const productinfo of arrproductInfo) {
|
||||||
// cerca nella tabella Product se esiste idProductInfo = _id e cancella tutti i record che hanno questa corrispondenza
|
// cerca nella tabella Product se esiste idProductInfo = _id e cancella tutti i record che hanno questa corrispondenza
|
||||||
if (Product) {
|
if (Product) {
|
||||||
await Product.deleteMany({ idProductInfo: productinfo._id });
|
await Product.updateMany(
|
||||||
|
{ idProductInfo: productinfo._id },
|
||||||
|
{ $set: { delete: true } }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ora rimuovi anche questo productInfo
|
// Ora rimuovi anche questo productInfo
|
||||||
await ProductInfo.deleteOne({ _id: productinfo._id });
|
await ProductInfo.updateOne(
|
||||||
|
{ _id: productinfo._id },
|
||||||
|
{ $set: { delete: true } }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ class CronMod {
|
|||||||
if (mydata.dbop === "") {
|
if (mydata.dbop === "") {
|
||||||
// } 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 === "ScraperDataAmazon") {
|
||||||
|
await ScraperDataAmazon(idapp, mydata.options)
|
||||||
} else if (mydata.dbop === "ReplaceAllCircuits") {
|
} else if (mydata.dbop === "ReplaceAllCircuits") {
|
||||||
// ++ Replace All Circuitname with 'Circuito RIS %s'
|
// ++ Replace All Circuitname with 'Circuito RIS %s'
|
||||||
await Circuit.replaceAllCircuitNames(idapp);
|
await Circuit.replaceAllCircuitNames(idapp);
|
||||||
|
|||||||
125
src/server/modules/Scraping.js
Normal file
125
src/server/modules/Scraping.js
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import cheerio from 'cheerio';
|
||||||
|
|
||||||
|
class AmazonBookScraper {
|
||||||
|
constructor() {
|
||||||
|
this.baseUrl = 'https://www.amazon.it/dp/';
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchPage(isbn) {
|
||||||
|
const url = `${this.baseUrl}${isbn}`;
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(url, {
|
||||||
|
headers: {
|
||||||
|
'User-Agent':
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' +
|
||||||
|
'AppleWebKit/537.36 (KHTML, like Gecko) ' +
|
||||||
|
'Chrome/113.0.0.0 Safari/537.36',
|
||||||
|
// altri header se necessario
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Errore fetching ISBN ${isbn}:`, err.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extractData(html) {
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
|
// Titolo
|
||||||
|
let title = $('#productTitle').text().trim() || null;
|
||||||
|
|
||||||
|
// Sottotitolo (Amazon spesso lo mette in #productSubtitle o nel titolo, proveremo)
|
||||||
|
let subtitle = $('#productSubtitle').text().trim() || null;
|
||||||
|
|
||||||
|
// Numero pagine, formato, edizione
|
||||||
|
// Questi dati spesso sono nella tabella dettagli prodotto con id #detailBullets_feature_div o #productDetailsTable
|
||||||
|
// Proviamo a estrarre da #detailBullets_feature_div
|
||||||
|
|
||||||
|
let pages = null;
|
||||||
|
let format = null;
|
||||||
|
let edition = null;
|
||||||
|
|
||||||
|
$('#detailBullets_feature_div li').each((i, el) => {
|
||||||
|
const label = $(el).find('span.a-text-bold').text().trim().toLowerCase();
|
||||||
|
const value = $(el).find('span').last().text().trim();
|
||||||
|
|
||||||
|
if (label.includes('pagine') || label.includes('pagine stampate')) {
|
||||||
|
pages = value;
|
||||||
|
} else if (label.includes('formato')) {
|
||||||
|
format = value;
|
||||||
|
} else if (label.includes('edizione')) {
|
||||||
|
edition = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// fallback su #productDetailsTable (altro possibile layout)
|
||||||
|
if (!pages || !format || !edition) {
|
||||||
|
$('#productDetailsTable .content tr').each((i, el) => {
|
||||||
|
const label = $(el).find('th').text().trim().toLowerCase();
|
||||||
|
const value = $(el).find('td').text().trim();
|
||||||
|
|
||||||
|
if (!pages && (label.includes('pagine') || label.includes('pagine stampate'))) {
|
||||||
|
pages = value;
|
||||||
|
} else if (!format && label.includes('formato')) {
|
||||||
|
format = value;
|
||||||
|
} else if (!edition && label.includes('edizione')) {
|
||||||
|
edition = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { title, subtitle, pages, format, edition };
|
||||||
|
}
|
||||||
|
|
||||||
|
async scrapeISBN(isbn) {
|
||||||
|
const html = await this.fetchPage(isbn);
|
||||||
|
if (!html) return null;
|
||||||
|
|
||||||
|
const data = this.extractData(html);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async scrapeMultiple(isbnList) {
|
||||||
|
const results = [];
|
||||||
|
for (const isbn of isbnList) {
|
||||||
|
console.log(`Scraping ISBN: ${isbn}`);
|
||||||
|
const data = await this.scrapeISBN(isbn);
|
||||||
|
results.push({ isbn, ...data });
|
||||||
|
// Per evitare blocchi, metti una pausa (es. 2 secondi)
|
||||||
|
await new Promise((r) => setTimeout(r, 2000));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function ScraperDataAmazon(idapp, options) {
|
||||||
|
const scraper = new AmazonBookScraper();
|
||||||
|
const isbn = options.isbn;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await scraper.scrapeISBN(isbn);
|
||||||
|
console.log(data);
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function ScraperMultipleDataAmazon(idapp, options) {
|
||||||
|
const scraper = new AmazonBookScraper();
|
||||||
|
const isbnList = ['8850224248']; // metti i tuoi ISBN qui
|
||||||
|
|
||||||
|
try {
|
||||||
|
const books = await scraper.scrapeMultiple(isbnList);
|
||||||
|
console.log(books);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AmazonBookScraper;
|
||||||
@@ -27,6 +27,8 @@ const Gasordine = require('../models/gasordine');
|
|||||||
|
|
||||||
const { User } = require('../models/user');
|
const { User } = require('../models/user');
|
||||||
|
|
||||||
|
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');
|
||||||
|
|
||||||
@@ -547,7 +549,8 @@ router.post('/join-pdf', authenticate, async (req, res) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (options.stampa) {
|
if (options.stampa) {
|
||||||
outputFileStampa = path.join(full_dir_out, path.basename(tools.removeFileExtension(outputFile))) + '-stampabile.pdf';
|
outputFileStampa =
|
||||||
|
path.join(full_dir_out, path.basename(tools.removeFileExtension(outputFile))) + '-stampabile.pdf';
|
||||||
// Creazione file per STAMPA
|
// Creazione file per STAMPA
|
||||||
const ris_stampa = await JoinPDFCatalogs(cataloghi, options, outputFileStampa, true);
|
const ris_stampa = await JoinPDFCatalogs(cataloghi, options, outputFileStampa, true);
|
||||||
if (ris_stampa) {
|
if (ris_stampa) {
|
||||||
@@ -2359,6 +2362,21 @@ router.post('/cloudflare', authenticate, async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('/scraper', authenticate, async (req, res) => {
|
||||||
|
const scraper = new AmazonBookScraper();
|
||||||
|
const isbn = req.data.options.isbn;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await scraper.scrapeISBN(isbn);
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
return res.send(data);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: '' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.post('/miab', authenticate, async (req, res) => {
|
router.post('/miab', authenticate, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
idapp = req.body.idapp;
|
idapp = req.body.idapp;
|
||||||
|
|||||||
@@ -534,14 +534,14 @@ connectToDatabase(connectionUrl, options)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// console.log('checkdir', folderprof);
|
// console.log('checkdir', folderprof);
|
||||||
if (!tools.existsSync(folderprof)) {
|
if (!tools.isFileExists(folderprof)) {
|
||||||
console.log('*** Creadir', folderprof);
|
console.log('*** Creadir', folderprof);
|
||||||
await fs.mkdirSync(folderprof);
|
await fs.mkdirSync(folderprof);
|
||||||
}
|
}
|
||||||
|
|
||||||
folderprof = dir + 'profile/' + myuser.username + '/' + table;
|
folderprof = dir + 'profile/' + myuser.username + '/' + table;
|
||||||
// console.log('checkdir', folderprof);
|
// console.log('checkdir', folderprof);
|
||||||
if (!tools.existsSync(folderprof)) {
|
if (!tools.isFileExists(folderprof)) {
|
||||||
console.log('creadir', folderprof);
|
console.log('creadir', folderprof);
|
||||||
await fs.mkdirSync(folderprof);
|
await fs.mkdirSync(folderprof);
|
||||||
}
|
}
|
||||||
@@ -691,10 +691,10 @@ connectToDatabase(connectionUrl, options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verifica esistenza file
|
// Verifica esistenza file
|
||||||
if (!tools.existsSync(keyPath)) {
|
if (!tools.isFileExists(keyPath)) {
|
||||||
throw new Error(`Chiave privata non trovata: ${keyPath}`);
|
throw new Error(`Chiave privata non trovata: ${keyPath}`);
|
||||||
}
|
}
|
||||||
if (!tools.existsSync(certPath)) {
|
if (!tools.isFileExists(certPath)) {
|
||||||
throw new Error(`Certificato non trovato: ${certPath}`);
|
throw new Error(`Certificato non trovato: ${certPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -944,7 +944,7 @@ connectToDatabase(connectionUrl, options)
|
|||||||
if (scriptProcess) scriptProcess.kill();
|
if (scriptProcess) scriptProcess.kill();
|
||||||
|
|
||||||
const scriptPath = path.join(__dirname, '..', '..', parsed.scriptName);
|
const scriptPath = path.join(__dirname, '..', '..', parsed.scriptName);
|
||||||
if (!tools.existsSync(scriptPath)) {
|
if (!tools.isFileExists(scriptPath)) {
|
||||||
return ws.send(JSON.stringify({ type: 'error', data: 'Script non trovato o non autorizzato' }));
|
return ws.send(JSON.stringify({ type: 'error', data: 'Script non trovato o non autorizzato' }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -445,7 +445,7 @@ class ImageDownloader {
|
|||||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
try {
|
try {
|
||||||
// Verifica se il filepath esiste già
|
// Verifica se il filepath esiste già
|
||||||
if (await this.existsSync(filepath)) {
|
if (await this.isFileExists(filepath)) {
|
||||||
fs.unlinkSync(filepath);
|
fs.unlinkSync(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +533,7 @@ class ImageDownloader {
|
|||||||
console.error(`❌ Errore nel tentativo ${attempt}/${maxRetries}:`, error.message);
|
console.error(`❌ Errore nel tentativo ${attempt}/${maxRetries}:`, error.message);
|
||||||
|
|
||||||
// Pulizia del file in caso di errore
|
// Pulizia del file in caso di errore
|
||||||
if (await this.existsSync(filepath)) {
|
if (await this.isFileExists(filepath)) {
|
||||||
fs.unlinkSync(filepath);
|
fs.unlinkSync(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,15 +554,6 @@ class ImageDownloader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async existsSync(tempFolder) {
|
|
||||||
try {
|
|
||||||
await fs.access(tempFolder);
|
|
||||||
// La directory esiste
|
|
||||||
} catch {
|
|
||||||
// La directory NON esiste
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Funzione per estrarre il nome del file dall'URL
|
// Funzione per estrarre il nome del file dall'URL
|
||||||
extractFileNameFromUrl(url) {
|
extractFileNameFromUrl(url) {
|
||||||
const match = url.match(/\/([^/?#]+)(?:[?#]|$)/);
|
const match = url.match(/\/([^/?#]+)(?:[?#]|$)/);
|
||||||
@@ -736,15 +727,6 @@ module.exports = {
|
|||||||
console.log(args);
|
console.log(args);
|
||||||
},
|
},
|
||||||
|
|
||||||
existsSync: async function (tempFolder) {
|
|
||||||
try {
|
|
||||||
await fs.access(tempFolder);
|
|
||||||
// La directory esiste
|
|
||||||
} catch {
|
|
||||||
// La directory NON esiste
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mylogserr: function (...args) {
|
mylogserr: function (...args) {
|
||||||
console.error(args);
|
console.error(args);
|
||||||
},
|
},
|
||||||
@@ -4204,7 +4186,7 @@ module.exports = {
|
|||||||
|
|
||||||
async mkdirpath(dirPath) {
|
async mkdirpath(dirPath) {
|
||||||
try {
|
try {
|
||||||
if (!await this.existsSync(dirPath)) {
|
if (!await this.isFileExists(dirPath)) {
|
||||||
fs.mkdirSync(dirPath, { recursive: true });
|
fs.mkdirSync(dirPath, { recursive: true });
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -4262,8 +4244,11 @@ module.exports = {
|
|||||||
|
|
||||||
async isFileExists(filename) {
|
async isFileExists(filename) {
|
||||||
try {
|
try {
|
||||||
return await this.existsSync(filename);
|
let fileExists = await fs.promises.stat(filename).then(() => true).catch(() => false);
|
||||||
|
// console.log(filename, 'esiste', fileExists)
|
||||||
|
return fileExists;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
// console.log(filename, 'esiste', 'FALSE')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -5976,7 +5961,7 @@ module.exports = {
|
|||||||
img = dir + img;
|
img = dir + img;
|
||||||
|
|
||||||
/*if (checkifExist) {
|
/*if (checkifExist) {
|
||||||
if (!this.existsSync(img)) {
|
if (!this.isFileExists(img)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
@@ -6150,9 +6135,9 @@ module.exports = {
|
|||||||
server_constants.DIR_UPLOAD + '/products/' + productInfo.image_link.split('/').pop();
|
server_constants.DIR_UPLOAD + '/products/' + productInfo.image_link.split('/').pop();
|
||||||
const savePath = path.resolve(__dirname, img); // Sostituisci con il percorso dove salvare l'immagine
|
const savePath = path.resolve(__dirname, img); // Sostituisci con il percorso dove salvare l'immagine
|
||||||
|
|
||||||
let scaricaimg = !productInfo.imagefile || !await this.existsSync(savePath);
|
let scaricaimg = !productInfo.imagefile || !await this.isFileExists(savePath);
|
||||||
|
|
||||||
if (!productInfo.imagefile && await this.existsSync(savePath)) {
|
if (!productInfo.imagefile && await this.isFileExists(savePath)) {
|
||||||
// esiste il file, ma sul DB non è corretto
|
// esiste il file, ma sul DB non è corretto
|
||||||
const stats = fs.statSync(savePath); // Ottieni informazioni sul file
|
const stats = fs.statSync(savePath); // Ottieni informazioni sul file
|
||||||
|
|
||||||
@@ -6166,7 +6151,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (productInfo.imagefile && await this.existsSync(savePath)) {
|
if (productInfo.imagefile && await this.isFileExists(savePath)) {
|
||||||
// esiste il file, ma sul DB non è corretto
|
// esiste il file, ma sul DB non è corretto
|
||||||
const stats = fs.statSync(savePath); // Ottieni informazioni sul file
|
const stats = fs.statSync(savePath); // Ottieni informazioni sul file
|
||||||
|
|
||||||
@@ -6209,7 +6194,7 @@ module.exports = {
|
|||||||
const filecompleto = path.resolve(__dirname, img); // Sostituisci con il percorso dove salvare l'immagine
|
const filecompleto = path.resolve(__dirname, img); // Sostituisci con il percorso dove salvare l'immagine
|
||||||
|
|
||||||
// Se non esiste lo scarico !
|
// Se non esiste lo scarico !
|
||||||
fileesistente = await this.existsSync(filecompleto);
|
fileesistente = await this.isFileExists(filecompleto);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vecchiomodo && (!productInfo.image_link || !fileesistente)) {
|
if (!vecchiomodo && (!productInfo.image_link || !fileesistente)) {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.2.46
|
1.2.47
|
||||||
Reference in New Issue
Block a user