Pourquoi j’ai créé cet email scraper Chrome
Tout a commencé avec un besoin très concret : je voulais inviter des entrepreneurs toulousains à mes afterworks mensuels Moovers. Le problème, c’est que les outils de prospection existants sont soit très chers (Hunter, Apollo, Kaspr à partir de 50-100€/mois), soit peu adaptés à la prospection locale par type de profession.
Google Maps est une mine d’or inexploitée pour ça. Tapez « plombier Toulouse » ou « coach sportif Lyon » et vous avez des centaines de fiches professionnelles avec des noms, des adresses, des téléphones — et parfois des emails. Le tout, totalement public. Il suffisait de trouver un moyen d’extraire tout ça automatiquement.
La deuxième idée est venue naturellement : et si on ne scrape pas que Google Maps, mais aussi les résultats de recherche web ? Quand quelqu’un cherche « plombier Toulouse » sur Google, les dix premières pages donnent accès à des centaines de sites de professionnels établis — des gens qui ont déjà investi dans leur présence digitale, donc des profils beaucoup plus qualifiés que la moyenne.
C’est comme ça qu’est né le projet : un seul outil, deux modes de scraping complémentaires, exportation automatique vers Google Drive, et intégration directe avec Brevo pour envoyer des campagnes email sans friction.
Comment fonctionne une extension Chrome — les bases techniques
Avant d’entrer dans le détail du code, il faut comprendre ce qu’est réellement une extension Chrome sous le capot. C’est un programme JavaScript qui s’exécute directement dans votre navigateur, avec accès aux pages que vous visitez. Elle se compose de plusieurs fichiers clés.
Le manifest.json — la carte d’identité de l’extension
C’est le fichier de configuration central. Il déclare les permissions dont l’extension a besoin (accès à l’onglet actif, stockage local, identité Google pour OAuth), les pages sur lesquelles les scripts s’injectent, et les informations générales comme le nom et la version. Sans ce fichier correctement configuré, rien ne fonctionne.
{
"manifest_version": 3,
"name": "Email Scraper Maps",
"version": "1.0",
"permissions": ["activeTab", "scripting", "storage", "identity"],
"host_permissions": ["https://www.google.com/*", "https://www.googleapis.com/*"],
"action": { "default_popup": "popup.html" },
"background": { "service_worker": "background.js" }
}
Le content script — celui qui lit les pages
Le content script est injecté dans les pages que vous visitez. Pour Google Maps, il parcourt le DOM de la page de résultats, extrait les noms d’établissements, clique sur chaque fiche pour en récupérer les détails (email, téléphone, site web), et renvoie ces données au script de fond.
Le background script — le cerveau de l’extension
Le background script (service worker en Manifest V3) coordonne tout. C’est lui qui reçoit les données du content script, les déduplique, gère l’upload vers Google Drive via l’API OAuth, et communique avec le popup pour afficher la progression.
Le popup — l’interface utilisateur
Le popup, c’est la petite fenêtre qui s’ouvre quand vous cliquez sur l’icône de l’extension. HTML + CSS + JavaScript pur. C’est là que vous saisissez votre mot-clé, choisissez le mode de scraping, et suivez la progression en temps réel.
Architecture de l’extension : les deux modes de scraping
L’une des décisions les plus importantes a été de construire deux modes distincts dans le même outil, parce qu’ils ne ciblent pas les mêmes profils de contacts.
Mode Google Maps — les professionnels locaux
Dans ce mode, l’extension s’appuie sur la page Google Maps déjà ouverte dans votre navigateur. Le content script injecté dans la page Maps parcourt les fiches visibles dans la colonne de gauche, clique automatiquement sur chacune d’elles, attend que les détails se chargent, puis extrait toutes les informations disponibles : nom de l’établissement, adresse, téléphone, URL du site web, et surtout l’email quand il est présent dans la fiche.
Le point délicat techniquement : Google Maps charge les fiches en lazy loading. L’extension doit donc gérer des délais d’attente intelligents, détecter quand une fiche est chargée, et simuler un comportement humain (pauses aléatoires entre chaque action) pour éviter d’être bloquée.
Mode Web Search — les professionnels établis
Ce mode fonctionne différemment : l’extension interroge DuckDuckGo (gratuit, sans limite d’API) avec le mot-clé que vous avez saisi, récupère les URLs des 10 premières pages de résultats, puis visite chaque site en arrière-plan pour y chercher des adresses email.
La détection d’emails dans une page web est plus complexe qu’il n’y paraît. Les emails peuvent être en clair dans le texte, cachés dans des liens mailto:, masqués par des techniques anti-spam (exemple : « contact [at] domaine [point] com »), ou même chargés dynamiquement via JavaScript. L’extension gère les cas les plus courants avec des expressions régulières robustes.
Ce mode est particulièrement efficace pour cibler des professionnels qui ont déjà un site web donc une présence digitale établie — un signal de qualification précieux.
Le défi de l’intégration Google Drive
C’est ici que les choses se sont vraiment compliquées. L’objectif était simple : à la fin de chaque scraping, l’extension exporte automatiquement un fichier CSV dans un dossier spécifique de Google Drive, sans que l’utilisateur ait à cliquer sur « Télécharger » et à déplacer le fichier manuellement.
En pratique, ça implique de gérer OAuth 2.0 depuis une extension Chrome — et c’est un sujet qui mérite un article entier à lui seul.
L’authentification OAuth depuis une extension
Une extension Chrome peut demander une authentification Google via l’API chrome.identity. Le flux est le suivant : l’utilisateur clique sur « Connecter Google Drive », Chrome affiche une fenêtre d’autorisation standard, l’utilisateur accepte, et l’extension reçoit un token d’accès valide pendant une heure.
Pour que ça fonctionne, il faut déclarer le client OAuth dans la Google Cloud Console, configurer les scopes nécessaires (drive.file pour n’écrire que dans les fichiers créés par l’extension, sans accès à tout le Drive), et référencer le client ID dans le manifest.json.
Le problème de la conversion automatique de Google
Premier problème rencontré : quand on uploadait le CSV via l’API Drive, Google le convertissait automatiquement en Google Sheets. Pratique dans certains cas, catastrophique ici — parce que les scripts Apps Script qui lisaient ces fichiers côté Moovers attendaient de vrais CSV, pas des Sheets.
La solution : ajouter le paramètre convert=false dans la requête d’upload, et forcer le MIME type à text/csv dans les métadonnées du fichier. Une ligne de code, mais qu’il fallait trouver.
const metadata = {
name: 'scraping_' + keyword + '_' + date + '.csv',
parents: ['VOTRE_FOLDER_ID_DRIVE'],
mimeType: 'text/csv'
};
const response = await fetch(
'https://www.googleapis.com/upload/drive/v3/files'
+ '?uploadType=multipart&convert=false',
{
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'multipart/related; boundary=boundary'
},
body: buildMultipartBody(metadata, csvContent)
}
);
L’intégration Brevo — de l’email scraping à la campagne en un clic
Une fois les emails collectés, encore faut-il pouvoir les utiliser. J’ai intégré Brevo (ex-Sendinblue) directement dans l’extension pour permettre l’import immédiat des contacts dans une liste, sans passer par l’interface web de Brevo.
Le flux est le suivant :
POST /v3/contacts/lists, puis importe tous les contacts via POST /v3/contacts/import.
Pour aller encore plus loin, j’ai ajouté un export automatique vers le dossier Google Drive csv_import_moovers à chaque scraping. Un Google Apps Script côté Drive surveille ce dossier et peut déclencher des actions supplémentaires automatiquement.
Le mode Batch — scraper 8 000 contacts en automatique
La fonctionnalité la plus puissante, construite dans les dernières versions, c’est le mode Batch. L’idée : au lieu de lancer des recherches une par une, vous renseignez une liste de villes et une liste de professions, et l’extension enchaîne toutes les combinaisons automatiquement, en tâche de fond.
Exemple concret : vous voulez toucher des artisans (plombiers, électriciens, maçons) dans 5 villes (Toulouse, Bordeaux, Lyon, Marseille, Nantes). Avec le mode Batch, vous entrez ces informations une fois, cliquez sur « Lancer », et l’extension génère et exécute les 15 recherches automatiquement — avec des pauses aléatoires entre chaque pour simuler une navigation humaine.
C’est exactement ce qu’on a utilisé pour scraper plus de 8 000 contacts à destination des campagnes Moovers sur Brevo. Chaque scraping prend environ 5 minutes par combinaison ville/profession — une bonne centaine de contacts en moyenne. Lancé un soir avant de dormir, vous vous réveillez avec une liste qualifiée prête à l’emploi.
Les problèmes rencontrés et leurs solutions
Je ne vais pas vous faire croire que tout s’est construit sans accrocs. Voici les principaux problèmes rencontrés et comment ils ont été résolus — parce que c’est souvent plus utile que les success stories.
Problème 1 : les onglets qui ne s’ouvrent pas
Dans les premières versions, l’extension essayait d’ouvrir un nouvel onglet Google Maps au moment du clic sur « GO ». Chrome bloque ce comportement depuis les popups d’extension pour des raisons de sécurité. La solution : l’extension doit d’abord s’assurer que Google Maps est déjà ouvert dans un onglet actif, puis injecter le content script dans cet onglet existant.
Problème 2 : les fichiers Drive convertis en Google Sheets
Évoqué plus haut — résolu avec convert=false et le bon MIME type. Ce bug a pris plusieurs itérations à identifier car il ne se manifestait que dans certains cas selon les paramètres de compte Google.
Problème 3 : les tokens OAuth qui expirent
Le token Google Drive est valide une heure. Si le batch de scraping dure plus longtemps, les uploads échouent silencieusement. La solution : vérifier la validité du token avant chaque upload et le rafraîchir automatiquement via chrome.identity.getAuthToken({ interactive: false }) si nécessaire.
Problème 4 : la déduplication des emails
Quand on enchaîne plusieurs scrapings sur des zones géographiques proches, certains contacts apparaissent dans plusieurs listes. J’ai développé un Google Apps Script séparé qui lit tous les CSV du dossier Drive, croise les emails, et génère une liste déduplication propre — sans doublon, triée par qualité de la fiche source.
Problème 5 : la mise à jour de l’extension sans la réinstaller
Chaque fois qu’on sortait une nouvelle version, le process naïf était : supprimer l’ancienne extension, dézipper la nouvelle, recharger. Trop lent et trop risqué (perte des paramètres stockés). Le bon process : garder toujours le même dossier sur le bureau, remplacer les fichiers modifiés, puis cliquer sur le bouton « Recharger » dans chrome://extensions. Les paramètres sont conservés dans le storage local de l’extension.
Le code de base pour démarrer
Voici une version simplifiée mais fonctionnelle du cœur de l’extension — suffisamment complète pour comprendre la mécanique et l’adapter à vos besoins.
manifest.json
{
"manifest_version": 3,
"name": "Email Scraper Maps",
"version": "1.0",
"description": "Scrape les emails depuis Google Maps et le web",
"permissions": ["activeTab", "scripting", "storage", "identity", "tabs"],
"host_permissions": [
"https://www.google.com/*",
"https://maps.google.com/*",
"https://www.googleapis.com/*",
"<all_urls>"
],
"oauth2": {
"client_id": "VOTRE_CLIENT_ID.apps.googleusercontent.com",
"scopes": ["https://www.googleapis.com/auth/drive.file"]
},
"action": { "default_popup": "popup.html" },
"background": { "service_worker": "background.js" }
}
content.js — extraction des emails depuis Google Maps
// Pause aléatoire anti-détection
function sleep(min, max) {
const ms = Math.floor(Math.random() * (max - min + 1)) + min;
return new Promise(r => setTimeout(r, ms));
}
// Extraction email depuis le texte d'une fiche
function extractEmail(text) {
const match = text.match(
/[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/
);
return match ? match[0].toLowerCase() : null;
}
// Scraping d'une fiche Maps ouverte
async function scrapeFiche() {
await sleep(800, 1800); // Pause humaine
const details = document.querySelector('[data-attrid="kc:/local:place"]');
const emailEl = document.querySelector('a[href^="mailto:"]');
const nameEl = document.querySelector('h1.DUwDvf');
return {
name: nameEl ? nameEl.textContent.trim() : '',
email: emailEl ? emailEl.href.replace('mailto:', '') : null,
source: 'Google Maps',
url: window.location.href
};
}
background.js — upload vers Google Drive
const DRIVE_FOLDER_ID = 'VOTRE_FOLDER_ID_ICI';
async function uploadCsvToDrive(csvContent, filename) {
// 1. Récupérer le token OAuth
const token = await new Promise((resolve, reject) => {
chrome.identity.getAuthToken({ interactive: true }, t => {
if (chrome.runtime.lastError) reject(chrome.runtime.lastError);
else resolve(t);
});
});
// 2. Construire le body multipart
const boundary = 'email_scraper_boundary';
const metadata = JSON.stringify({
name: filename,
parents: [DRIVE_FOLDER_ID],
mimeType: 'text/csv'
});
const body = [
'--' + boundary,
'Content-Type: application/json',
'',
metadata,
'--' + boundary,
'Content-Type: text/csv',
'',
csvContent,
'--' + boundary + '--'
].join('
');
// 3. Upload avec convert=false
const response = await fetch(
'https://www.googleapis.com/upload/drive/v3/files'
+ '?uploadType=multipart&convert=false',
{
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'multipart/related; boundary=' + boundary
},
body: body
}
);
if (!response.ok) {
const err = await response.json();
throw new Error(err.error?.message || 'Upload Drive échoué');
}
return await response.json();
}
Ce que vous pouvez faire avec cet outil
Au-delà de mon cas d’usage Moovers, les applications sont nombreuses dès lors qu’on a besoin de constituer une base de contacts qualifiés localement.
Cibler des artisans, commerçants, professions libérales dans une ville précise pour proposer vos services (communication, SEO, comptabilité, assurance…).
Inviter des professionnels d’une catégorie spécifique à des conférences, afterworks, salons ou ateliers. C’est l’usage principal pour Moovers.
Constituer un panel de professionnels à contacter pour un sondage, une étude qualitative ou une validation de concept.
Identifier des partenaires potentiels dans votre secteur pour des collaborations, prescriptions ou co-marketing.
Limites légales et bonnes pratiques RGPD
Je ne peux pas conclure cet article sans aborder la question légale. Collecter des emails de professionnels est une zone grise en France et en Europe. Voici ce qu’il faut savoir.
En B2B, la prospection par email est autorisée sans consentement préalable à condition que l’email soit en rapport direct avec la profession du destinataire, que chaque email comporte une mention de désinscription claire, et que vous respectiez les demandes de suppression dans les plus brefs délais.
Les emails professionnels visibles publiquement sur Google Maps (contact@plombier-toulouse.fr) entrent généralement dans ce cadre. En revanche, les emails personnels (jean.dupont@gmail.com récupérés sur un profil Maps) sont à éviter absolument — ils relèvent de la vie privée et leur utilisation à des fins commerciales sans consentement est illégale.
Mon conseil pratique : dans vos campagnes email, soyez ultra-clair sur qui vous êtes, pourquoi vous contactez cette personne, et facilitez-lui au maximum la désinscription. Une prospection transparente et respectueuse convertit mieux qu’une approche agressive — et elle vous évite des plaintes CNIL.
Pour aller plus loin
L’extension que je vous ai décrite ici est celle que j’utilise en conditions réelles pour Moovers. Elle est arrivée à sa version 2.26 après des dizaines d’itérations, de bugs corrigés, de fonctionnalités ajoutées. Elle n’est pas parfaite — aucun outil ne l’est — mais elle fait ce pour quoi elle a été construite avec une fiabilité suffisante pour des usages professionnels.
Si vous souhaitez construire votre propre version ou adapter ce code à votre cas d’usage, le code de base présenté dans cet article est un bon point de départ. Les principaux défis techniques à anticiper : la gestion du lazy loading de Maps, l’authentification OAuth Drive, la robustesse de la détection d’emails dans des pages HTML hétérogènes, et le comportement anti-détection.
Si vous voulez qu’on travaille ensemble sur un outil similaire ou une stratégie de prospection digitale pour votre activité, je suis disponible pour en discuter.
Un projet de scraping ou de prospection digitale ?
Discutons de votre cas d’usage — je peux vous accompagner sur la stratégie ou le développement.













