Il est crucial pour les entreprises ou indépendants de disposer de bases de données clients B2B complètes et à jour. Souvent, vous n'avez en main que le nom d'une entreprise et vous ne disposez pas du numéro de téléphone, ni d'un email valide, ni même de l'URL de son site. Dans ce cas, nous pouvons vous aider à récupérer automatiquement ces informations grâce au web scraping.
Une fois le processus mis en place, cela permet d'industrialiser l'acquisition d'informations clients afin d'optimiser vos prospections commerciales.
Dans cet article, je vais vous montrer comment enrichir vos bases de données client B2B en Python, notamment via le web scraping. L’exemple ci-dessous illustre comment, à partir du nom de l’entreprise, vous pouvez lancer une recherche Google pour récupérer la première URL, puis en extraire des données supplémentaires telles que le logo, le numéro de téléphone, l’email ou les liens vers les réseaux sociaux.
Attention : l’accès automatisé à Google est soumis à des conditions d’utilisation et peut rapidement se heurter à des blocages (CAPTCHA, etc.). Une solution alternative peut être d’utiliser l’API officielle de Google (Custom Search JSON API) ou un service tiers. Le code présenté ici n’est qu’un exemple à adapter pour respecter les CGU de Google.
Notre base de données
Imaginons que vous disposiez d’un fichier (CSV ou JSON) contenant uniquement des noms d’entreprise. Votre objectif est d’enrichir cette base de données pour y ajouter :
- Le site web (récupéré automatiquement via la recherche Google).
- Les coordonnées de l’entreprise (email, téléphone).
- Les liens vers les réseaux sociaux (Facebook, LinkedIn, YouTube).
- L’URL du logo de l’entreprise.
Voici un exemple de notre base de donnée :
Avant
[ { "client_name": "Google" }, { "client_name": "Meta" }, { "client_name": "Microsoft", "client_website": "https://www.microsoft.com" } ]
Après
[ { "client_name": "Google", "client_website": "https://www.google.com", "image": "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", "email": "contact@google.com", "telephone": "+33123456789", "facebook": "https://www.facebook.com/Google", "linkedin": "https://www.linkedin.com/company/google/", "youtube": "https://www.youtube.com/user/Google" }, { "client_name": "Meta", "client_website": "https://about.facebook.com/meta", "image": "https://about.facebook.com/logo/meta.png", "email": "info@meta.com", "telephone": "+33109876543", "facebook": "https://www.facebook.com/Meta", "linkedin": "https://www.linkedin.com/company/facebook/", "youtube": "https://www.youtube.com/user/Facebook" }, { "client_name": "Microsoft", "client_website": "https://www.microsoft.com", "image": "https://www.microsoft.com/logo.png", "email": "support@microsoft.com", "telephone": "+33123450000", "facebook": "https://www.facebook.com/Microsoft", "linkedin": "https://www.linkedin.com/company/microsoft/", "youtube": "https://www.youtube.com/microsoft" } ]
Prérequis
Before you begin, make sure you have installed the following libraries:
- requests : pour effectuer des requêtes HTTP.
- beautifulsoup4 : pour analyser le HTML des pages web.
- psycopg2 : pour interagir avec PostgreSQL (si vous souhaitez stocker les données en base).
- concurrent.futures : pour le traitement concurrent des données.
- googlesearch-python (ou équivalent) : pour effectuer une recherche Google automatisée.
Installation avec pip :
pip install requests beautifulsoup4 psycopg2 concurrent.futures googlesearch-python
La bibliothèque googlesearch-python n’est pas officiellement maintenue par Google. Vous pouvez également chercher d’autres alternatives ou utiliser l’API officielle de Google.
Étape 1 : Configuration initiale
Nous commençons par importer les bibliothèques nécessaires et définir un en-tête User-Agent commun pour imiter un navigateur réel. Cela aide à éviter d’être systématiquement bloqué par certains sites web.
import json import psycopg2 import requests from bs4 import BeautifulSoup import re from urllib.parse import urljoin import concurrent.futures # Import pour la recherche Google try: from googlesearch import search except ImportError: print("Veuillez installer la bibliothèque googlesearch-python ou configurer l'API Google.") # Définir un en-tête User-Agent pour simuler un navigateur réel. HEADERS = { "User-Agent": ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/115.0.0.0 Safari/537.36" ) } # Créer une session HTTP persistante pour réutiliser les connexions. session = requests.Session() session.headers.update(HEADERS)
Step 2: Data Extraction Function
The function extract_logo_email_phone_social is the heart of web scraping. It takes a URL as input and attempts to extract the logo, email, phone number, and links to social media (Facebook, LinkedIn, YouTube) from the website.
def extract_logo_email_phone_social(client_url): # Initialisation des variables de retour avec des chaînes vides image_url = "" email = "" telephone = "" facebook = "" linkedin = "" youtube = "" # On sauvegarde l'URL d'origine pour référence original_url = client_url try: # Tenter de récupérer la page avec un timeout de 10 secondes. response = session.get(client_url, timeout=10) except Exception: # En cas d'échec, on essaie de remplacer http par https (si applicable) if client_url.startswith("http://"): https_url = client_url.replace("http://", "https://", 1) try: response = session.get(https_url, timeout=10) client_url = https_url # Mise à jour de l'URL si le HTTPS fonctionne except Exception: # Retourne des valeurs vides si la requête échoue. return "", "", "", "", "", "" else: return "", "", "", "", "", "" # Vérification du statut de la réponse if response.status_code == 200: soup = BeautifulSoup(response.text, 'html.parser') # Recherche d'une image de logo for img in soup.find_all("img"): src = img.get("src", "") alt = img.get("alt", "") title = img.get("title", "") if "logo" in src.lower() or "logo" in alt.lower() or "logo" in title.lower(): if src.lower().endswith((".png", ".jpg", ".jpeg", ".svg")): image_url = urljoin(client_url, src) break # Extraction du texte brut de la page pour chercher l'email et le téléphone text = soup.get_text() email_match = re.search(r'[\w\.-]+@[\w\.-]+\.\w+', text) if email_match: email = email_match.group(0) # Extraction d'éventuels numéros de téléphone phone_candidates = re.findall(r'[\d\-\s\(\)]{10,}', text) for candidate in phone_candidates: digits = re.sub(r'\D', '', candidate) if 10 <= len(digits) <= 16: # Longueur plausible if digits.startswith("33"): telephone = "+" + digits break elif digits.startswith("0"): telephone = digits break # Recherche des liens vers les réseaux sociaux for a in soup.find_all("a"): href = a.get("href", "") if href: lower_href = href.lower() if "facebook" in lower_href and not facebook: facebook = urljoin(client_url, href) if "linkedin" in lower_href and not linkedin: linkedin = urljoin(client_url, href) if "youtube" in lower_href and not youtube: youtube = urljoin(client_url, href) return image_url, email, telephone, facebook, linkedin, youtube
Étape 3 : Fonction de recherche Google (si aucune URL n’est connue)
La fonction get_first_google_result va chercher le premier lien renvoyé par Google pour un nom d’entreprise donné. Nous n’utilisons ici qu’une requête simple, sans paramètre précis. Dans un usage réel, vous devriez gérer les cas d’échec, les blocages, et potentiellement configurer l’API Custom Search de Google.
def get_first_google_result(company_name): try: # On effectue une recherche Google et on retourne le premier résultat. for url in search(company_name, num=1, stop=1): return url except Exception as e: print(f"Erreur lors de la recherche Google pour {company_name} : {e}") return ""
Étape 4 : Traitement d’un enregistrement
La fonction process_record traite chaque enregistrement (ou « client ») de votre fichier JSON :
- Récupère le nom du client.
- Si vous n’avez pas d’URL, effectue la recherche Google pour récupérer le premier lien.
- Appelle la fonction d’extraction pour récupérer des données supplémentaires.
def process_record(record): # On suppose que chaque record est un dict avec une clé "client_name" au minimum. props = record company_name = props.get("client_name") client_website = props.get("client_website", "") # Si le site web n'existe pas, on fait une recherche Google if not client_website and company_name: client_website = get_first_google_result(company_name) if client_website: image, email, telephone, facebook, linkedin, youtube = extract_logo_email_phone_social(client_website) else: # Valeurs vides si la recherche a échoué ou qu'il n'y a pas de nom d'entreprise image, email, telephone, facebook, linkedin, youtube = "", "", "", "", "", "" # On retourne un tuple pour la suite du traitement return (props, client_website, image, email, telephone, facebook, linkedin, youtube)
Step 4: Loading GeoJSON data
Vous pouvez stocker vos données dans un fichier JSON (ou autre). Voici un exemple de chargement :
with open("clients_data.json", "r", encoding="utf-8") as f: data = json.load(f) records = data # data est censé être une liste de dictionnaires
Étape 6 : Traitement concurrent des enregistrements
Pour accélérer le processus, nous utilisons concurrent.futures.ThreadPoolExecutor afin de gérer plusieurs enregistrements simultanément (surtout utile si vous avez un grand nombre d'entreprises à traiter).
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: results = list(executor.map(process_record, records))
Step 6: Connecting to PostgreSQL and creating the table
Si vous souhaitez stocker le résultat dans une base de données, vous pouvez utiliser PostgreSQL. Voici un exemple de création de table :
conn = psycopg2.connect( host="", database="", user="", password="", port="" ) cur = conn.cursor() cur.execute("DROP TABLE IF EXISTS clients;") cur.execute(""" CREATE TABLE clients ( id SERIAL PRIMARY KEY, client_name TEXT, client_website TEXT, industry TEXT, address TEXT, city TEXT, country TEXT, image TEXT, email TEXT, telephone TEXT, facebook TEXT, linkedin TEXT, youtube TEXT ); """) conn.commit()
Étape 8 : Insertion des données dans la base
Enfin, insérez chaque enregistrement enrichi dans la base de données :
for result in results: props, client_website, image, email, telephone, facebook, linkedin, youtube = result cur.execute(""" INSERT INTO clients ( client_name, client_website, industry, address, city, country, image, email, telephone, facebook, linkedin, youtube ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s); """, ( props.get("client_name"), client_website, props.get("industry", ""), props.get("address", ""), props.get("city", ""), props.get("country", ""), image, email, telephone, facebook, linkedin, youtube )) conn.commit() cur.close() conn.close()
Conclusion
En suivant ces étapes, vous pouvez enrichir vos bases de données clients B2B avec des informations souvent manquantes. Lorsque vous ne possédez que le nom d’une entreprise, vous pouvez :
- Rechercher automatiquement l’URL via Google (en veillant à respecter les CGU et à gérer les éventuels blocages).
- Scraper ce site avec BeautifulSoup pour extraire email, téléphone, liens vers les réseaux sociaux, etc.
- Insérer ou mettre à jour votre base de données (PostgreSQL ou autre).
Le web scraping, combiné à de la recherche Google automatisée, offre une méthode flexible pour collecter des données. N’oubliez pas de respecter les conditions d’utilisation des sites que vous visitez et de prévoir une gestion robuste des exceptions (timeouts, redirections, captchas, etc.). Vous pouvez naturellement personnaliser ce script selon vos besoins pour récupérer d’autres champs ou cibler d’autres sources de données.