scrape-with-ai / scraper.py
PyQuarX's picture
Update scraper.py
3d4df23 verified
raw
history blame
5.5 kB
import tempfile
import os
import shutil # Nécessaire pour supprimer le dossier temporaire
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import traceback # Pour afficher les erreurs détaillées
def scrape_website(website):
"""
Scrape le contenu HTML d'un site web en utilisant Selenium et ChromeDriver.
Args:
website (str): L'URL du site web à scraper.
Returns:
str or None: Le contenu HTML brut de la page, ou None en cas d'erreur.
"""
print(f"Préparation du scraping pour : {website}")
chrome_driver_path = "/usr/bin/chromedriver" # Assurez-vous que ce chemin est correct sur HF Spaces
# Ou essayez sans si chromedriver est dans le PATH
options = Options()
options.add_argument("--headless") # Exécuter sans interface graphique (essentiel pour les serveurs)
options.add_argument("--no-sandbox") # Requis pour les environnements type Docker/HF Spaces
options.add_argument("--disable-dev-shm-usage") # Évite les problèmes de mémoire partagée limitée
options.add_argument("--disable-gpu") # Désactiver l'accélération GPU, souvent inutile en headless
options.add_argument("window-size=1920x1080") # Définir une taille de fenêtre virtuelle
# --- Gestion du répertoire de données utilisateur ---
# Crée un répertoire temporaire unique pour cette session Chrome
user_data_dir = tempfile.mkdtemp()
print(f"Utilisation du répertoire de données utilisateur temporaire : {user_data_dir}")
options.add_argument(f"--user-data-dir={user_data_dir}")
# Note : Si vous n'avez absolument pas besoin de persistance (cookies, etc.),
# vous pouvez commenter les deux lignes ci-dessus et celle du nettoyage dans finally.
# Ne pas spécifier de user-data-dir du tout est souvent plus simple si possible.
driver = None # Initialiser à None pour le bloc finally
html_content = None # Initialiser le résultat
try:
# --- Initialisation du WebDriver ---
# L'objet options est passé directement à webdriver.Chrome, pas à Service
service = Service(executable_path=chrome_driver_path)
print("Lancement du navigateur Chrome headless...")
driver = webdriver.Chrome(service=service, options=options)
print("Navigateur lancé.")
print(f"Accès à l'URL : {website}")
driver.get(website)
print("Page chargée.")
# Attendre un peu si nécessaire pour le contenu dynamique (optionnel)
# import time
# time.sleep(2) # Attendre 2 secondes par exemple
html_content = driver.page_source
print("Code source HTML récupéré.")
except Exception as e:
print(f"ERREUR lors du scraping de {website}: {e}")
print("Traceback complet :")
traceback.print_exc() # Affiche la trace complète pour un meilleur débogage
finally:
# --- Nettoyage ---
if driver:
print("Fermeture du WebDriver.")
driver.quit() # Ferme le navigateur et le processus chromedriver
# Supprimer le répertoire de données utilisateur temporaire
if os.path.exists(user_data_dir):
try:
print(f"Suppression du répertoire temporaire : {user_data_dir}")
shutil.rmtree(user_data_dir)
except OSError as e:
print(f"Erreur lors de la suppression de {user_data_dir}: {e}")
return html_content
def extract_body_content(html_content):
"""
Extrait le contenu de la balise <body> d'un contenu HTML.
Args:
html_content (str): Le contenu HTML brut.
Returns:
str: Le contenu de la balise <body>, ou une chaîne vide si non trouvé.
"""
if not html_content:
return ""
soup = BeautifulSoup(html_content, "html.parser")
body = soup.body
if body:
return str(body)
print("Balise <body> non trouvée dans le HTML.")
return ""
def clean_body_content(body_content):
"""
Nettoie le contenu HTML en retirant les scripts, styles et les espaces superflus.
Args:
body_content (str): Le contenu HTML (généralement de la balise <body>).
Returns:
str: Le texte nettoyé.
"""
if not body_content:
return ""
soup = BeautifulSoup(body_content, "html.parser")
# Supprimer les balises <script> et <style>
for script_or_style in soup(["script", "style"]):
script_or_style.extract()
# Obtenir le texte, en mettant une nouvelle ligne comme séparateur
cleaned_text = soup.get_text(separator="\n", strip=True)
# Optionnel : Nettoyer les lignes vides multiples si get_text ne suffit pas
# lines = [line.strip() for line in cleaned_text.splitlines() if line.strip()]
# cleaned_text = "\n".join(lines)
return cleaned_text
def split_dom_content(dom_content, max_length=60000):
"""
Divise une longue chaîne de caractères en morceaux de taille maximale spécifiée.
Args:
dom_content (str): La chaîne de caractères à diviser.
max_length (int): La longueur maximale de chaque morceau.
Returns:
list[str]: Une liste de chaînes de caractères.
"""
if not dom_content:
return []
return [
dom_content[i:i + max_length] for i in range(0, len(dom_content), max_length)
]