refact(webhook): corrige integracao do webhook e trata erros de cookies
- Migra arquivos de webhook de TS para JS - Corrige imports quebrados e destructuring de SendMessageWebhook e ErrorType - Trata arquivo cookies.json vazio/invalido com try/catch - Corrige digitação de porcentagemPromo no ProductEntity - Envia eventos de sucesso para busca_produto e erros para error_busca
This commit is contained in:
69
package-lock.json
generated
69
package-lock.json
generated
@@ -10,6 +10,7 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"axios": "^1.16.1",
|
||||
"discord-webhook-node": "^1.1.8",
|
||||
"puppeteer": "^25.0.4",
|
||||
"puppeteer-extra": "^3.3.6",
|
||||
"puppeteer-extra-plugin-stealth": "^2.11.2"
|
||||
@@ -441,6 +442,32 @@
|
||||
"integrity": "sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/discord-webhook-node": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/discord-webhook-node/-/discord-webhook-node-1.1.8.tgz",
|
||||
"integrity": "sha512-3u0rrwywwYGc6HrgYirN/9gkBYqmdpvReyQjapoXARAHi0P0fIyf3W5tS5i3U3cc7e44E+e7dIHYUeec7yWaug==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"form-data": "^3.0.0",
|
||||
"node-fetch": "^2.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/discord-webhook-node/node_modules/form-data": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz",
|
||||
"integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.35"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -1017,6 +1044,26 @@
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
@@ -1437,6 +1484,12 @@
|
||||
"b4a": "^1.6.4"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typed-query-selector": {
|
||||
"version": "2.12.2",
|
||||
"resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz",
|
||||
@@ -1458,6 +1511,22 @@
|
||||
"integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
|
||||
10
package.json
10
package.json
@@ -1,19 +1,21 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"axios": "^1.16.1",
|
||||
"discord-webhook-node": "^1.1.8",
|
||||
"puppeteer": "^25.0.4",
|
||||
"puppeteer-extra": "^3.3.6",
|
||||
"puppeteer-extra-plugin-stealth": "^2.11.2"
|
||||
},
|
||||
"name": "codevscodesjs",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node src/index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
const ErrorType = require('../../webhook/ErrorType');
|
||||
const SendMessageWebhook = require('../../webhook/webhook');
|
||||
const ProductEntity = require('../domain/ProductEntity');
|
||||
|
||||
class ProcessPromotionsUseCase {
|
||||
@@ -24,7 +26,10 @@ class ProcessPromotionsUseCase {
|
||||
}
|
||||
}
|
||||
|
||||
SendMessageWebhook('Processo finalizado!', `${enviados} produtos foram enviados para a API.`, ErrorType.busca_produto);
|
||||
|
||||
console.log(`Processo finalizado! ${enviados} produtos foram enviados para a API.`);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
class ProductEntity {
|
||||
constructor({ nomeProduto, precoOriginal, precoPromocao, porcetagemPromo, imagem, linkProduto }) {
|
||||
constructor({ nomeProduto, precoOriginal, precoPromocao, porcentagemPromo, imagem, linkProduto }) {
|
||||
this.nomeProduto = nomeProduto || 'sem título';
|
||||
this.precoOriginal = precoOriginal || 0;
|
||||
this.precoPromocao = precoPromocao || 0;
|
||||
this.porcetagemPromo = porcetagemPromo || 0;
|
||||
this.porcentagemPromo = porcentagemPromo || 0;
|
||||
this.imagem = imagem || '';
|
||||
this.linkProduto = linkProduto || '';
|
||||
this.plataforma = 'Mercado Livre'; // Regra de negócio fixa para este robô
|
||||
|
||||
@@ -2,21 +2,23 @@ const puppeteer = require('puppeteer-extra');
|
||||
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
|
||||
puppeteer.use(StealthPlugin());
|
||||
const fs = require('fs');
|
||||
const SendMessageWebhook = require('../../webhook/webhook');
|
||||
const ErrorType = require('../../webhook/ErrorType');
|
||||
|
||||
class AffiliateGenerator {
|
||||
async converterLista(produtosBrutos) {
|
||||
console.log('\nIniciando conversão para links de afiliado (Modo Docker/Invisível)...');
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
headless: false,
|
||||
const browser = await puppeteer.launch({
|
||||
headless: false,
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-blink-features=AutomationControlled',
|
||||
'--disable-gpu',
|
||||
'--window-size=1920,1080'
|
||||
]
|
||||
]
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
|
||||
@@ -25,8 +27,19 @@ class AffiliateGenerator {
|
||||
|
||||
// 2. Injeta os cookies de autorização
|
||||
if (fs.existsSync('./cookies.json')) {
|
||||
const cookies = JSON.parse(fs.readFileSync('./cookies.json', 'utf8'));
|
||||
await page.setCookie(...cookies);
|
||||
try {
|
||||
const rawCookies = fs.readFileSync('./cookies.json', 'utf8').trim();
|
||||
if (rawCookies) {
|
||||
const cookies = JSON.parse(rawCookies);
|
||||
await page.setCookie(...cookies);
|
||||
console.log('✅ Cookies injetados com sucesso.');
|
||||
} else {
|
||||
console.log('⚠️ O arquivo cookies.json está vazio.');
|
||||
}
|
||||
} catch (erro) {
|
||||
console.error('❌ Erro ao ler ou analisar o cookies.json:', erro.message);
|
||||
SendMessageWebhook('Erro nos Cookies!', `Falha ao processar cookies.json: ${erro.message}`, ErrorType.error_busca);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Acessa o gerador com a sessão já "aquecida"
|
||||
@@ -35,6 +48,7 @@ class AffiliateGenerator {
|
||||
try {
|
||||
await page.waitForSelector('textarea#url-0', { timeout: 15000 });
|
||||
} catch (erro) {
|
||||
SendMessageWebhook('Erro crítico!', 'Bloqueio detectado ou cookies inválidos.', ErrorType.error_busca);
|
||||
console.log('\n❌ ERRO CRÍTICO: Bloqueio detectado ou cookies inválidos.');
|
||||
await browser.close();
|
||||
return []; // Retorna array vazio para não quebrar a API com Erro 500
|
||||
@@ -65,9 +79,11 @@ class AffiliateGenerator {
|
||||
produtosConvertidos.push(produto); // Só adiciona se a conversão foi um sucesso
|
||||
console.log(`✅ Convertido: ${produto.nomeProduto.substring(0, 30)}...`);
|
||||
} else {
|
||||
SendMessageWebhook('Erro na conversão!', `Link inválido ou não gerado para o produto: ${produto.nomeProduto}`, ErrorType.error_busca);
|
||||
throw new Error("Link inválido ou não gerado.");
|
||||
}
|
||||
} catch (error) {
|
||||
SendMessageWebhook('Erro na conversão!', `Erro ao gerar link de afiliado para o produto: ${produto.nomeProduto}`, ErrorType.error_busca);
|
||||
console.log(`⚠️ Descartado (Falha na conversão): ${produto.nomeProduto.substring(0, 30)}...`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
const axios = require('axios');
|
||||
const SendMessageWebhook = require('../../webhook/webhook');
|
||||
const ErrorType = require('../../webhook/ErrorType');
|
||||
|
||||
class ApiClient {
|
||||
constructor(baseURL) {
|
||||
@@ -19,6 +21,7 @@ class ApiClient {
|
||||
await axios.post(this.urlDestino, payload);
|
||||
console.log(`✅ Enviado com sucesso: ${produto.nomeProduto}`);
|
||||
} catch (erro) {
|
||||
SendMessageWebhook('Erro ao enviar!', `Erro ao enviar o produto para a API: ${erro.message}`, ErrorType.error_busca);
|
||||
console.log(`❌ Erro ao enviar ${produto.nomeProduto} | Motivo: ${erro.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
const puppeteer = require('puppeteer-extra');
|
||||
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
|
||||
const SendMessageWebhook = require('../../webhook/webhook');
|
||||
const ErrorType = require('../../webhook/ErrorType');
|
||||
|
||||
// Ativa o modo de camuflagem para evitar detecção
|
||||
puppeteer.use(StealthPlugin());
|
||||
@@ -8,13 +10,13 @@ class MercadoLivreScraper {
|
||||
async extrairDados() {
|
||||
console.log('Iniciando extração de promoções do Mercado Livre...');
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
headless: true,
|
||||
const browser = await puppeteer.launch({
|
||||
headless: true,
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-blink-features=AutomationControlled'
|
||||
]
|
||||
]
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
|
||||
@@ -68,6 +70,7 @@ class MercadoLivreScraper {
|
||||
return resultados;
|
||||
});
|
||||
|
||||
SendMessageWebhook('Processo finalizado!', `${produtos.length} produtos foram encontrados.`, ErrorType.busca_produto);
|
||||
console.log(`\n--- DIAGNÓSTICO FINAL ---`);
|
||||
console.log(`O robô enxergou ${produtos.length} cartões na página em modo invisível.`);
|
||||
console.log(`-------------------------\n`);
|
||||
@@ -76,6 +79,7 @@ class MercadoLivreScraper {
|
||||
return produtos;
|
||||
|
||||
} catch (error) {
|
||||
SendMessageWebhook('Erro durante a extração!', `Erro durante a extração: ${error.message}`, ErrorType.error_busca);
|
||||
console.error('Erro durante a extração:', error.message);
|
||||
await browser.close();
|
||||
return [];
|
||||
|
||||
7
webhook/ErrorType.js
Normal file
7
webhook/ErrorType.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const ErrorType = {
|
||||
busca_produto: "https://discord.com/api/webhooks/1511503190489825280/JmeEKSpkUtBzhBrUKLE8aOp0W_8aUVpYUktpWonHuynYFOJgKiJp31MRreJpjmwLv868",
|
||||
error_busca: "https://discord.com/api/webhooks/1510999432039239832/Vq82_mb0ThlM6Py6KbAF-QPV4r_SPEE5Tvk5vLJadSYdIlKAVUMUdqT_7jcBJV6u2ddl"
|
||||
|
||||
}
|
||||
|
||||
module.exports = ErrorType;
|
||||
18
webhook/webhook.js
Normal file
18
webhook/webhook.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const { Webhook } = require('discord-webhook-node');
|
||||
|
||||
|
||||
function SendMessageWebhook(title, description, webhookUrl) {
|
||||
let url = webhookUrl;
|
||||
let content = `**${title}**\n${description}`;
|
||||
|
||||
if (!url) {
|
||||
// Fallback for 2 arguments: SendMessageWebhook(content, url)
|
||||
url = description;
|
||||
content = title;
|
||||
}
|
||||
|
||||
const hook = new Webhook(url);
|
||||
hook.send(content);
|
||||
}
|
||||
|
||||
module.exports = SendMessageWebhook;
|
||||
Reference in New Issue
Block a user