Comment Aspirer un Site Web Complet en HTML avec Python


Introduction

Que ce soit pour une sauvegarde locale, un accĂšs hors ligne, une migration vers un autre CMS ou une veille concurrentielle, aspirer un site web est une tĂąche essentielle en web scraping. L’objectif est de rĂ©cupĂ©rer l’intĂ©gralitĂ© des pages HTML, les images, les fichiers multimĂ©dias et les documents liĂ©s, tout en prĂ©servant l’arborescence du site.

Dans ce guide, nous verrons comment aspirer n’importe quel site web en Python en utilisant Selenium, Requests, BeautifulSoup, et en optimisant la gestion des ressources.


Pourquoi Aspirer un Site Web ?

✔ Archivage : Conserver une copie statique d’un site web 📂
✔ Consultation hors ligne : AccĂ©der au contenu sans connexion Internet 🚀
✔ Migration vers un autre CMS : RĂ©cupĂ©rer toutes les pages et fichiers 📩
✔ Sauvegarde de documentation : Garder des copies locales pour rĂ©fĂ©rence 📜
✔ Scraping d’informations : Extraire des donnĂ©es pertinentes pour analyse 📊


1ïžâƒŁ PrĂ©-requis Techniques

Avant de commencer, assurez-vous d’avoir installĂ© les outils nĂ©cessaires :

pip install selenium requests beautifulsoup4

Vous aurez également besoin de :

  • Google Chrome et ChromeDriver (pour Selenium)
  • Un accĂšs au site web cible, avec ou sans authentification

2ïžâƒŁ Configuration du Script

Nous allons configurer notre script pour rĂ©cupĂ©rer l’ensemble du site, en tĂ©lĂ©chargeant les pages HTML, les fichiers multimĂ©dias et les documents liĂ©s.

import logging
import os
import time
import requests
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from urllib.parse import urlparse, unquote, parse_qs, urljoin
from bs4 import BeautifulSoup

# Configuration du site Ă  aspirer
SITE_URL = "https://example.com"
LOGIN_URL = "https://example.com/login"
USERNAME = "your_username"
PASSWORD = "your_password"
OUTPUT_FOLDER = "./site_mirror"

3ïžâƒŁ Lancement du Navigateur et Authentification (Si NĂ©cessaire)

Selenium nous permet d’interagir avec des sites protĂ©gĂ©s par un login.

def setup_browser():
    """Initialisation de Selenium avec Chrome en mode headless."""
    logging.info("Configuration du navigateur...")
    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")
    options.add_argument("--window-size=1920,1080")
    service = Service("/usr/bin/chromedriver")
    return webdriver.Chrome(service=service, options=options)

def login_to_site(browser):
    """Connexion au site via Selenium."""
    browser.get(LOGIN_URL)
    WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.NAME, "username")))

    browser.find_element(By.NAME, "username").send_keys(USERNAME)
    browser.find_element(By.NAME, "password").send_keys(PASSWORD)
    browser.find_element(By.NAME, "password").submit()

    time.sleep(2)
    logging.info("Connexion réussie.")

4ïžâƒŁ Capturer les Cookies pour Requests

Selenium permet l’authentification, mais Requests est plus rapide pour le tĂ©lĂ©chargement des ressources.

def capture_cookies(browser):
    """Extrait les cookies de Selenium et les transmet Ă  Requests."""
    cookies = browser.get_cookies()
    session_cookies = {cookie['name']: cookie['value'] for cookie in cookies}
    logging.info("Cookies capturés : %s", session_cookies)
    return session_cookies

5ïžâƒŁ CrĂ©ation d’une Arborescence BasĂ©e sur l’URL

Nous devons recréer la structure des pages web localement.

def generate_local_path(url, output_folder):
    """CrĂ©e un chemin de fichier basĂ© sur l’URL."""
    parsed_url = urlparse(url)
    path = unquote(parsed_url.path.strip("/"))

    if not path or path.endswith("/"):
        path = os.path.join(path, "index.html")
    else:
        path += ".html"

    local_path = os.path.join(output_folder, path)
    os.makedirs(os.path.dirname(local_path), exist_ok=True)
    return local_path

6ïžâƒŁ Exporter et Sauvegarder les Pages

Nous utilisons BeautifulSoup pour récupérer un HTML propre.

def save_page(browser, url, output_folder):
    """Télécharge et sauvegarde une page HTML."""
    browser.get(url)
    time.sleep(2)

    file_path = generate_local_path(url, output_folder)

    with open(file_path, "w", encoding="utf-8") as f:
        f.write(browser.page_source)
    logging.info("Page exportée : %s", file_path)

    return file_path

7ïžâƒŁ TĂ©lĂ©charger les Ressources (Images, PDF, etc.)

Nous devons modifier les liens dans les pages HTML pour pointer vers des fichiers locaux.

def download_resources(browser, html_content, output_folder, base_url, file_path):
    """Télécharge toutes les ressources liées (images, fichiers)."""
    soup = BeautifulSoup(html_content, "html.parser")
    cookies = capture_cookies(browser)

    for img in soup.find_all("img"):
        img_url = urljoin(base_url, img["src"])
        local_path = download_file_with_cookies(img_url, cookies, output_folder, "media/images")
        if local_path:
            img["src"] = os.path.relpath(local_path, os.path.dirname(file_path))

    for link in soup.find_all("a"):
        href = link.get("href")
        if href and href.startswith("/") and (".pdf" in href or ".docx" in href):
            file_url = urljoin(base_url, href)
            local_path = download_file_with_cookies(file_url, cookies, output_folder, "documents")
            if local_path:
                link["href"] = os.path.relpath(local_path, os.path.dirname(file_path))

    with open(file_path, "w", encoding="utf-8") as f:
        f.write(str(soup))
    logging.info("Ressources liées téléchargées et mises à jour.")

8ïžâƒŁ Exploration RĂ©cursive du Site

Nous allons parcourir toutes les pages et les enregistrer.

def crawl_site(browser, start_url, output_folder):
    """Parcourt toutes les pages du site et les télécharge."""
    visited = set()
    to_visit = [start_url]

    while to_visit:
        url = to_visit.pop(0)
        if url in visited:
            continue

        file_path = save_page(browser, url, output_folder)
        visited.add(url)

        soup = BeautifulSoup(browser.page_source, "html.parser")
        for link in soup.find_all("a"):
            href = link.get("href")
            if href and href.startswith("/") and href not in visited:
                to_visit.append(urljoin(SITE_URL, href))

    logging.info("Exploration terminée.")

đŸ”č ExĂ©cuter le Script

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    browser = setup_browser()
    login_to_site(browser)
    crawl_site(browser, SITE_URL, OUTPUT_FOLDER)
    browser.quit()

Conclusion

✅ Aspirer un site web complet est possible avec Python et Selenium.
✅ Ce script garde l’arborescence et tĂ©lĂ©charge toutes les ressources liĂ©es.
✅ Vous obtenez un export propre et structurĂ© en HTML.

🚀 AmĂ©liorations possibles ? Ajouter le support pour des sites JavaScript-heavy (via Playwright) ou exporter en PDF !

💡 Si ce guide vous a aidĂ©, partagez-le et optimisez votre scraping ! 🎯