0% ont trouvé ce document utile (0 vote)
14 vues14 pages

Dans Python

Le document décrit la configuration d'une application Node.js utilisant SendGrid pour l'envoi d'emails à partir de données Excel. Il inclut des instructions pour installer des dépendances, configurer des templates d'email, et mettre en place un serveur Express pour traiter les requêtes d'envoi d'emails et de scraping via Puppeteer. Le code gère également le scraping de Google Maps et la sauvegarde des résultats en JSON et CSV.

Transféré par

Bentardeit Sarra
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
14 vues14 pages

Dans Python

Le document décrit la configuration d'une application Node.js utilisant SendGrid pour l'envoi d'emails à partir de données Excel. Il inclut des instructions pour installer des dépendances, configurer des templates d'email, et mettre en place un serveur Express pour traiter les requêtes d'envoi d'emails et de scraping via Puppeteer. Le code gère également le scraping de Google Maps et la sauvegarde des résultats en JSON et CSV.

Transféré par

Bentardeit Sarra
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Dans python_email

npm install @sendgrid/mail

Créer .env et met


SENDGRID_API_KEY=SG.jj_YZZqtTYOYSoxxs15YWw.hx6Vb3pc19hKZ9xbiAllcj6EfgDb6d8TfgmMTnEn4C
E
Et dans [Link] met
import express from 'express';

import cors from 'cors';

import bodyParser from 'body-parser';

import multer from 'multer';

import xlsx from 'xlsx';

import fs from 'fs';

import path from 'path';

import sgMail from '@sendgrid/mail';

import { fileURLToPath } from 'url';

import templates from './[Link]'; // Assure-toi que c'est bien un export ES module

const __filename = fileURLToPath([Link]);

const __dirname = [Link](__filename);

const app = express();

const PORT = 3000;

[Link]([Link].SENDGRID_API_KEY);

[Link](cors());

[Link]([Link]());

[Link]([Link]([Link](__dirname, '..', 'frontend')));

const upload = multer({ dest: 'uploads/' });

[Link]('/api/send-from-excel', [Link]('file'), async (req, res) => {

const { templateId, subject, message } = [Link];

const file = [Link];


[Link](' Body reçu :', [Link]);

[Link](' Fichier reçu :', file ? [Link] : 'Aucun fichier');

if (!file) return [Link](400).json({ error: 'Fichier manquant' });

if (!subject) return [Link](400).json({ error: 'Sujet manquant' });

if (!templateId && (!message || [Link]() === '')) {

return [Link](400).json({ error: 'Template ou message requis' });

let baseContent = (message && [Link]() !== '') ? message : templates[templateId];

if (!baseContent) return [Link](404).json({ error: 'Template introuvable' });

try {

const workbook = [Link]([Link]);

const sheetName = [Link][0];

const worksheet = [Link][sheetName];

const rows = [Link].sheet_to_json(worksheet);

[Link](' Données Excel chargées:', rows);

[Link]([Link]);

const results = [];

for (const [index, row] of [Link]()) {

[Link](` Ligne ${index + 1}:`, row);

// Recherche clé email sans tenir compte de la casse

const emailKey = [Link](row).find(k => [Link]() === 'email');


if (!emailKey || !row[emailKey]) {

[Link](` Ligne ${index + 1}: Email manquant ou clé incorrecte`);

[Link]({ row, status: 'Erreur: Email manquant' });

continue;

let emailContent = baseContent;

for (const key in row) {

if ([Link](key)) {

const regex = new RegExp(`{{\\s*${key}\\s*}}`, 'gi');

emailContent = [Link](regex, row[key]);

const msg = {

to: row[emailKey],

from: 'comparateur@[Link]',

subject,

text: emailContent,

};

try {

await [Link](msg);

[Link](` Email envoyé à ${row[emailKey]}`);

[Link]({ row, status: 'Envoyé' });

} catch (err) {

[Link](` Erreur envoi email à ${row[emailKey]}:`, [Link]);

[Link]({ row, status: 'Erreur: ' + [Link] });

}
[Link]({ message: 'Envoi depuis fichier Excel terminé', details: results });

} catch (err) {

[Link](' Erreur lors du traitement du fichier:', err);

[Link](500).json({ error: 'Erreur lors du traitement du fichier' });

});

[Link]('/api/templates', (req, res) => {

[Link](templates);

});

[Link](PORT, () => {

[Link](`Serveur backend démarré sur [Link]

});

Dans [Link] met


const templates = {

'1': `Bonjour {{ prénom }},

Nous avons une offre spéciale rien que pour vous !

Cordialement,

L’équipe Dashboard Automations`,

'2': `Bonjour {{ prénom }},

Vous êtes cordialement invité(e) à notre prochain événement.

Au plaisir de vous y voir !


L’équipe Dashboard Automations`,

'3': `Bonjour {{ prénom }},

Je me permets de revenir vers vous concernant notre dernière discussion.

N’hésitez pas à me contacter.

L’équipe Dashboard Automations`

};

export default templates;

et dans [Link] met


"name": "python_email",

"version": "1.0.0",

"type": "module",

Pour scrapping met dans [Link]

import puppeteer from "puppeteer-extra";

import StealthPlugin from "puppeteer-extra-plugin-stealth";

import fs from "fs";

import cliProgress from "cli-progress";

import { Parser } from "json2csv";

[Link](StealthPlugin());

function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));

function isBrowserActive(browser) {

return browser && [Link]();

function savePartialResults(result, filePath = "results_detailed.json") {

let existingResults = [];

if ([Link](filePath)) {

try {

const fileData = [Link](filePath, "utf-8");

existingResults = fileData ? [Link](fileData) : [];

} catch (error) {

[Link]("⚠ Erreur lors de la lecture du JSON :", [Link]);

existingResults = [];

[Link](result);

[Link](filePath, [Link](existingResults, null, 2), "utf-8");

async function scrapeGoogleMaps(searchQuery) {

const browser = await [Link]({ headless: false, args: ["--no-sandbox"] });

if (!isBrowserActive(browser)) {

[Link](" Le navigateur Puppeteer ne s'est pas lancé correctement.");

return [];

const page = await [Link]();


try {

await [Link]("[Link] { waitUntil: "networkidle2", timeout: 60000


});

await [Link]("body", { timeout: 10000 });

[Link](` Recherche en cours pour : ${searchQuery}`);

await delay(5000);

await [Link]('div[role="feed"]', { timeout: 60000 });

[Link](" Chargement des résultats...");

await [Link](async () => {

const wrapper = [Link]('div[role="feed"]');

await new Promise(resolve => {

let previousHeight = 0;

let sameHeightCount = 0;

const distance = 1000;

const scrollDelay = 1000;

const timer = setInterval(() => {

[Link](0, distance);

if (previousHeight === [Link]) {

sameHeightCount++;

} else {

sameHeightCount = 0;

previousHeight = [Link];

if (sameHeightCount >= 3) {

clearInterval(timer);

resolve();

}
}, scrollDelay);

});

});

const results = await [Link](() => {

return [Link]([Link]('div[role="feed"] > div'))

.map(item => ({

title: [Link]('.fontHeadlineSmall')?.innerText || "N/A",

link: [Link]('a')?.href || "N/A"

}))

.filter(result => [Link] !== "N/A");

});

[Link](` ${[Link]} lieux trouvés.`);

if (!isBrowserActive(browser)) {

throw new Error("⚠ Le navigateur Puppeteer s'est fermé prématurément avant d'extraire les
détails.");

const progressBar = new [Link]({}, [Link].shades_classic);

[Link]([Link], 0);

const detailedResults = [];

for (let i = 0; i < [Link]; i++) {

const detail = await scrapeDetailPage(results[i], browser);

savePartialResults(detail);

[Link](detail);

[Link](i + 1);

}
[Link]();

[Link]("results_detailed.json", [Link](detailedResults, null, 2), "utf-8");

[Link](" Les résultats ont été sauvegardés dans `results_detailed.json`");

try {

const parser = new Parser();

const csv = [Link](detailedResults);

[Link]("results_detailed.csv", csv, "utf-8");

[Link](" Les résultats ont également été sauvegardés dans `results_detailed.csv`");

} catch (csvError) {

[Link](" Erreur lors de la conversion en CSV :", csvError);

return detailedResults;

} catch (error) {

[Link](" Erreur lors du scraping :", [Link]);

[Link]([Link]);

return [];

} finally {

if (isBrowserActive(browser)) {

[Link](" Fermeture du navigateur...");

await [Link]();

async function scrapeDetailPage(result, browser) {

if (!isBrowserActive(browser)) {

[Link](`⚠ Le navigateur Puppeteer est fermé. Impossible de récupérer ${[Link]}`);

return { title: [Link], error: "Navigateur fermé avant extraction" };


}

let detailPage;

try {

detailPage = await [Link]();

await [Link]([Link], { waitUntil: "networkidle2", timeout: 30000 });

await delay(1000);

const detail = await [Link](() => {

const title = [Link]("h1[class^='DUwDvf'], h1[class*='x3AX1']")?.innerText ||


"Non disponible";

const rating = [Link]("span.F7nice, span[aria-label*='étoiles']")?.textContent


|| "Non disponible";

const reviews = [Link]("button[aria-label*='avis'], span[aria-


label*='avis']")?.textContent || "Non disponible";

const address = [Link]("button[data-item-id='address'], div[aria-


label='Adresse']")?.innerText || "Non disponible";

let phone = [Link]("button[data-tooltip='Copier le numéro de téléphone'],


span[aria-label*='Téléphone']")?.innerText || "Non disponible";

const website = [Link]("a[data-tooltip='Ouvrir le site Web'],


a[href*='http']")?.href || "Non disponible";

if (phone === "Non disponible") {

const pageText = [Link];

const phonePattern = /(?:\+?\d{1,3})?\s?(?:\(?\d{2,4}\)?\s?)?\d{2,4}[-.\s]?\d{2,4}[-


.\s]?\d{2,4}/g;

const phoneMatch = [Link](phonePattern);

if (phoneMatch) {

phone = phoneMatch[0];

return { title, rating, reviews, address, phone, website };

});
[Link](` Détails récupérés pour : ${[Link]}`);

return detail;

} catch (error) {

[Link](` Erreur pour ${[Link]} :`, [Link]);

return { title: [Link], error: [Link] };

} finally {

if (detailPage && ![Link]()) {

await [Link]();

// Export pour utilisation dans Express

export async function scrapeGoogleMapsAPI(searchQuery) {

return scrapeGoogleMaps(searchQuery);

// Si script lancé directement en CLI

if ([Link] === `[Link] {

const searchQuery = [Link][2] || "café lac1";

scrapeGoogleMaps(searchQuery);

Et dans [Link]
import express from "express";

import cors from "cors";

import path, { dirname } from "path";

import { fileURLToPath } from "url";


import { scrapeGoogleMapsAPI } from "./[Link]";

const __filename = fileURLToPath([Link]);

const __dirname = dirname(__filename);

const app = express();

const PORT = 4000;

// Middleware pour autoriser CORS et parser JSON

[Link](cors());

[Link]([Link]());

// Log à chaque requête reçue (middleware)

[Link]((req, res, next) => {

[Link](`[${new Date().toISOString()}] Requête reçue : ${[Link]} ${[Link]}`);

next();

});

[Link]("/scrape", async (req, res) => {

[Link](" Route POST /scrape appelée");

[Link](" Body reçu :", [Link]);

try {

const { keyword } = [Link];

if (!keyword) {

[Link]("⚠ Mot-clé absent dans la requête");

return [Link](400).json({ error: "Le mot-clé est requis." });

[Link](" Démarrage du scraping avec keyword :", keyword);


const results = await scrapeGoogleMapsAPI(keyword);

[Link](` Scraping terminé avec ${[Link]} résultats`);

[Link](200).json({ message: "Scraping terminé avec succès.", results });

} catch (error) {

[Link](" Erreur capturée dans /scrape :", error);

[Link](500).json({ error: "Erreur lors du scraping", details: [Link] });

});

[Link]("/", (req, res) => {

[Link]("GET / - Envoi de la page [Link]");

[Link]([Link](__dirname, "frontend", "[Link]"));

});

[Link](PORT, () => {

[Link](` Serveur démarré sur [Link]

});

Vous aimerez peut-être aussi