commit 40d23113f73954cb3adb21d5de7977f4e87e17d5 Author: Djeex Date: Fri Feb 14 13:46:07 2025 +0000 1st commit diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bda0eae --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +# Utilise une image officielle de Python avec les outils nécessaires +FROM python:3.9-slim + +# Installe les dépendances requises pour Selenium et Chrome +RUN apt-get update && apt-get install -y \ + curl unzip wget xvfb \ + && rm -rf /var/lib/apt/lists/* + +# Télécharge et installe Google Chrome +RUN wget -qO- https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor > /usr/share/keyrings/google-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/google-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | tee /etc/apt/sources.list.d/google-chrome.list \ + && apt-get update \ + && apt-get install -y google-chrome-stable \ + && rm -rf /var/lib/apt/lists/* + +# Télécharge et installe le ChromeDriver correspondant +RUN CHROME_VERSION=$(google-chrome --version | awk '{print $3}' | cut -d '.' -f 1) \ + && wget -O /tmp/chromedriver.zip "https://chromedriver.storage.googleapis.com/${CHROME_VERSION}.0/chromedriver_linux64.zip" \ + && unzip /tmp/chromedriver.zip -d /usr/local/bin/ \ + && rm /tmp/chromedriver.zip \ + && chmod +x /usr/local/bin/chromedriver + +# Définit le répertoire de travail +WORKDIR /app + +# Copie les fichiers nécessaires +COPY requirements.txt . +COPY .env . +COPY Nvidia_Stock_Checker.py ./script.py # Adapte le nom du fichier si nécessaire + +# Installe les dépendances Python +RUN pip install --no-cache-dir -r requirements.txt + +# Commande pour exécuter le script +CMD ["python", "script.py"] diff --git a/docker/.env b/docker/.env new file mode 100644 index 0000000..33b4aba --- /dev/null +++ b/docker/.env @@ -0,0 +1,20 @@ +# URL de la page Nvidia à surveiller +URL="https://marketplace.nvidia.com/fr-fr/consumer/graphics-cards/?locale=fr-fr&page=1&limit=12&gpu=RTX%205090&manufacturer=NVIDIA&manufacturer_filter=NVIDIA~1" + +# Nombre de cycles de vérification avant d'arrêter (1 = une seule vérification) +ITER_CYCLES=1 + +# Temps d'attente après le chargement de la page (en secondes) +WAIT_TIME=3 + +# Intervalle entre chaque vérification (en secondes) +RUN_INTERVAL=30 + +# Afficher le body HTML de la page pour débogage (TRUE/FALSE) +PRINT_BODY=FALSE + +# Activer les alertes en cas d'erreur (TRUE/FALSE) +ERROR_ALERT=FALSE + +# Webhook Discord pour envoyer des notifications en cas de stock disponible +DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/XXXXXX/XXXXXXXXX" diff --git a/docker/compose.yml b/docker/compose.yml new file mode 100644 index 0000000..e69de29 diff --git a/nvidia-stock-bot.py b/nvidia-stock-bot.py new file mode 100644 index 0000000..317b97f --- /dev/null +++ b/nvidia-stock-bot.py @@ -0,0 +1,122 @@ +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.chrome.options import Options +import time +import traceback +from dotenv import load_dotenv +import os +import requests + +# Charger les variables d'environnement depuis le fichier .env +load_dotenv() + +URL_NVIDIA = os.getenv( + "URL", + "https://marketplace.nvidia.com/fr-fr/consumer/graphics-cards/?locale=fr-fr&page=1&limit=12&gpu=RTX%205090&manufacturer=NVIDIA&manufacturer_filter=NVIDIA~1" +) + +N = int(os.getenv("ITER_CYCLES", 1)) +WAIT_TIME = int(os.getenv("WAIT_TIME", 3)) +RUN_INTERVAL = int(os.getenv("RUN_INTERVAL", 30)) +PRINT_BODY = os.getenv("PRINT_BODY", "FALSE").lower() == "true" +ERROR_ALERT = os.getenv("ERROR_ALERT", "FALSE").lower() == "true" +DISCORD_WEBHOOK_URL = os.getenv("DISCORD_WEBHOOK_URL", "") + +# Variable pour stocker l'état du stock (évite les notifications répétées) +previous_stock_state = False # False = hors stock, True = en stock + +def send_discord_message(message: str): + if not DISCORD_WEBHOOK_URL: + print("Aucun webhook Discord défini (DISCORD_WEBHOOK_URL).") + return + + data = {"content": message} + try: + response = requests.post(DISCORD_WEBHOOK_URL, json=data) + if response.status_code >= 400: + print(f"Erreur lors de l'envoi du message Discord : {response.text}") + else: + print("Message Discord envoyé avec succès.") + except Exception as e: + print(f"Exception lors de l'envoi du message Discord : {e}") + +def check_stock_button(driver): + """ + Vérifie si le bouton indiquant une rupture de stock est présent. + Retourne True si stock disponible, False sinon. + """ + try: + out_of_stock_buttons = driver.find_elements(By.XPATH, "//button[contains(@class, 'stock-grey-out')]") + return not bool(out_of_stock_buttons) + except Exception as e: + print(f"Erreur lors de la vérification du stock : {e}") + return False + +def checkStockNvidia(): + global previous_stock_state + + chrome_options = Options() + chrome_options.add_argument("--headless") + chrome_options.add_argument("--no-sandbox") + chrome_options.add_argument("--disable-gpu") + chrome_options.add_argument("--disable-notifications") + chrome_options.add_argument("--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " + "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36") + + driver = webdriver.Chrome(options=chrome_options) + + for i in range(N): + try: + driver.get(URL_NVIDIA) + time.sleep(WAIT_TIME) # Attente fixe après chargement de la page + + if PRINT_BODY: + print("===== BODY START =====") + print(driver.page_source) + print("===== BODY END =====") + + is_available = check_stock_button(driver) + + if is_available and not previous_stock_state: + message = { + "title": f"🚀 RTX 5090 FE en stock !", + "description": f":point_right: **[Achetez ici](https://marketplace.nvidia.com/fr-fr/consumer/graphics-cards/?locale=fr-fr&page=1&limit=12&gpu=RTX%205090,RTX%205080&manufacturer=NVIDIA)**", + "color": 3066993, # Couleur verte + "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()), + #"thumbnail": { + # "url": "https://www.nvidia.com/content/dam/en-zz/Solutions/geforce/graphic-cards/50-series/rtx-5090/geforce-rtx-5090-learn-more-og-1200x630.jpg" + #} + } + + payload = { + "content": "@everyone", + "username": "Nvidia Bot", + "embeds": [message] + } + + send_discord_message(message) + previous_stock_state = True # Met à jour l'état du stock + elif not is_available: + previous_stock_state = False # Remet à zéro pour permettre une future notification + + except Exception as e: + print("ERREUR DURANT UNE VÉRIFICATION :") + traceback.print_exc() + if ERROR_ALERT: + send_discord_message(f"Erreur dans le script :\n```\n{traceback.format_exc()}\n```") + + driver.quit() + +if __name__ == "__main__": + print(f"Script démarré. Vérification toutes les {RUN_INTERVAL} secondes...") + while True: + try: + checkStockNvidia() + except Exception as e: + print("ERREUR GLOBALE : ") + traceback.print_exc() + if ERROR_ALERT: + send_discord_message(f"Erreur globale dans le script :\n```\n{traceback.format_exc()}\n```") + + print(f"Prochaine vérification dans {RUN_INTERVAL} secondes...") + time.sleep(RUN_INTERVAL) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b8255ec --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +selenium +python-dotenv +requests \ No newline at end of file