Idle Bot in Python probieren

  • Registrierung ist offen, allerdings wurden web.de und gmx.de als Mailanbieter gesperrt. Es gibt aktuell ein Problem mit dem Mailserver, demnach landen die Mails derzeit meistens im Spam.

JadenDx

Member
Member
May 6, 2024
30
4
8
Moin Männers, ich versuche mich heute zum ersten mal an etwas Coding und habe absolut keine Ahnung und ich hab das mit ChatGPT erstellt.
Ich möchte in einem Idle game Monster killen. Mein Problem ist, dass der xpath für die Monster nur die Nummern der möglichen 8 Monsterplätze sind. Deshalb habe ich es mit Screenshot abgleichen versucht, was gar nicht funktioniert hat.


Python:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
import time
import pyautogui  # Für das Simulieren von Mausaktionen

# Anmeldedaten direkt im Skript (nicht empfohlen für Produktion)
EMAIL = '---'
PASSWORD = '---'

# Browser-Optionen konfigurieren
options = Options()
options.headless = False
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)

# XPaths und Namen zuweisen
XPATHS = {
    'login_link': '/html/body/div[2]/div[1]/div/p[2]/a',
    'email_field': '//*[@id="email"]',
    'password_field': '//*[@id="password"]',
    'hunt_button': '//*[@id="game-container"]/div/div[2]/div[1]/div[1]/div[2]/div/div[2]/div[2]/button',
    'ogre_button': '//*[@id="game-container"]/div/div[2]/div[1]/div[1]/div[2]/div/div[1]/button[8]/img',
    'buffalo_button': '//*[@id="game-container"]/div[2]/div[2]/div[1]/div[1]/div[2]/div/div[1]/button[5]/img',
    'spectre_button': '//*[@id="game-container"]/div/div[2]/div[1]/div[1]/div[2]/div/div[1]/button[6]/img'
}

def click_monster(xpath, wait_time):
    """Klickt auf ein Monster, wenn es vorhanden ist, und wartet eine bestimmte Zeit."""
    try:
        monster_button = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, xpath)))
        monster_button.click()
        time.sleep(1)  # Warte 1 Sekunde vor dem Mausklick für den Kampf
        # Klicke auf die gegebene Position, um den Kampf zu starten
        pyautogui.click(x=482, y=758)
        time.sleep(wait_time)
        return True
    except Exception as e:
        print(f"Fehler beim Klicken auf Monster mit XPath {xpath}: {e}")
        return False

def all_monsters_absent():
    """Überprüft, ob alle Monster auf der Seite nicht vorhanden sind."""
    for xpath in XPATHS.values():
        if xpath != XPATHS['hunt_button']:  # Den "Hunt"-Button überspringen
            try:
                WebDriverWait(driver, 1).until(EC.presence_of_element_located((By.XPATH, xpath)))
                return False
            except:
                continue
    return True

try:
    # Schritt 1: Gehe zur Startseite und logge dich ein
    driver.get('https://web.idle-mmo.com/')
    print("Navigiere zur Startseite...")

    login_link = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, XPATHS['login_link'])))
    login_link.click()
    time.sleep(1)  # Warte 1 Sekunde, bis die Seite vollständig geladen ist

    print("Geben Sie E-Mail-Adresse und Passwort ein...")

    email_field = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, XPATHS['email_field'])))
    email_field.send_keys(EMAIL)
    password_field = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, XPATHS['password_field'])))
    password_field.send_keys(PASSWORD)
    password_field.send_keys(Keys.RETURN)
    time.sleep(1)  # Warte 1 Sekunde, um die Anmeldung abzuschließen

    # Navigiere zur Battle-Seite
    print("Navigiere zur Battle-Seite...")
    driver.get('https://web.idle-mmo.com/battle')
    time.sleep(1)  # Warte 1 Sekunde, bis die Battle-Seite vollständig geladen ist

    while True:
        # Schritt 2: Klicke auf den "Hunt"-Button und warte 107 Sekunden
        print("Klicke auf den 'Hunt'-Button...")
        hunt_button = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, XPATHS['hunt_button'])))
        hunt_button.click()
        time.sleep(107)  # Warte 107 Sekunden

        # Schritt 3: Klickt auf die vorhandenen Monster, bis keine mehr vorhanden sind
        monster_active = True
        while monster_active:
            monster_active = False  # Nehme an, dass keine Monster vorhanden sind
            if click_monster(XPATHS['ogre_button'], 92):
                monster_active = True
            elif click_monster(XPATHS['buffalo_button'], 104):
                monster_active = True
            elif click_monster(XPATHS['spectre_button'], 52):
                monster_active = True

        # Wenn keine Monster mehr vorhanden sind, beginne erneut von Schritt 2
        if all_monsters_absent():
            print("Keine Monster mehr vorhanden. Beginne erneut von Schritt 2...")
            driver.get('https://web.idle-mmo.com/battle')
            time.sleep(1)  # Warte 1 Sekunde, bis die Battle-Seite vollständig geladen ist

finally:
    print("Drücke Enter, um den Browser zu schließen...")
    input()
    driver.quit()

Ich habe hier zu Testzwecken Schritt 2 weggelassen, weil das jedes mal fast 2 Minuten dauert und das Spectre Monster eh gerade auf der Seite vorhanden wäre

Python:
import cv2
import numpy as np
import pyautogui
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Bild-Pfad
SPECTRE_IMAGE_PATH = r'C:\Users\g-tow\OneDrive\Desktop\Neuer Ordner (6)\spectre.png'

# Browser-Optionen konfigurieren
options = Options()
options.headless = False
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)

# XPaths und Namen zuweisen
XPATHS = {
    'login_link': '/html/body/div[2]/div[1]/div/p[2]/a',
    'email_field': '//*[@id="email"]',
    'password_field': '//*[@id="password"]',
    'battle_page': 'https://web.idle-mmo.com/battle'
}

def locate_and_click_image(image_path, wait_time):
    """Sucht nach einem Bild auf dem Bildschirm und klickt darauf, wenn es gefunden wird."""
    # Screenshot der aktuellen Ansicht
    screenshot = pyautogui.screenshot()
    screenshot.save('screenshot.png')  # Speichern des Screenshots
    
    # Bild und Screenshot laden
    image = cv2.imread(image_path)
    screenshot = cv2.imread('screenshot.png')

    # Umwandlung der Bilder in Graustufen für bessere Übereinstimmung
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    screenshot_gray = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)

    # Bildvergleich durchführen
    result = cv2.matchTemplate(screenshot_gray, image_gray, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    
    if max_val > 0.8:  # Schwellwert für die Bilderkennung
        # Berechne die Position des gefundenen Bildes
        top_left = max_loc
        height, width = image_gray.shape[:2]
        bottom_right = (top_left[0] + width, top_left[1] + height)
        
        # Klicke auf das Bild
        pyautogui.click(x=top_left[0] + width / 2, y=top_left[1] + height / 2)
        time.sleep(1)  # Warte 1 Sekunde vor dem Mausklick für den Kampf
        # Klicke auf die gegebene Position, um den Kampf zu starten
        pyautogui.click(x=482, y=758)
        time.sleep(wait_time)
        return True
    return False

def all_monsters_absent():
    """Überprüft, ob alle Monster auf der Seite nicht vorhanden sind."""
    return not locate_and_click_image(SPECTRE_IMAGE_PATH, 0)  # Keine Wartezeit, nur Prüfung

try:
    # Schritt 1: Gehe zur Startseite und logge dich ein
    driver.get('https://web.idle-mmo.com/')
    print("Navigiere zur Startseite...")

    login_link = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, XPATHS['login_link'])))
    login_link.click()
    time.sleep(1)  # Warte 1 Sekunde, bis die Seite vollständig geladen ist

    print("Geben Sie E-Mail-Adresse und Passwort ein...")

    email_field = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, XPATHS['email_field'])))
    password_field = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, XPATHS['password_field'])))
    password_field.send_keys(Keys.RETURN)
    time.sleep(1)  # Warte 1 Sekunde, um die Anmeldung abzuschließen

    # Navigiere zur Battle-Seite
    print("Navigiere zur Battle-Seite...")
    driver.get(XPATHS['battle_page'])
    time.sleep(1)  # Warte 1 Sekunde, bis die Battle-Seite vollständig geladen ist

    while True:
        # Schritt 3: Klickt auf die vorhandenen Monster, bis keine mehr vorhanden sind
        monster_active = True
        while monster_active:
            monster_active = locate_and_click_image(SPECTRE_IMAGE_PATH, 52)

        # Wenn keine Monster mehr vorhanden sind, lade die Battle-Seite neu
        if all_monsters_absent():
            print("Keine Monster mehr vorhanden. Lade die Battle-Seite neu...")
            driver.get(XPATHS['battle_page'])
            time.sleep(1)  # Warte 1 Sekunde, bis die Battle-Seite vollständig geladen ist

finally:
    print("Drücke Enter, um den Browser zu schließen...")
    input()
    driver.quit()

Hab gestern Abend noch mit tesseract getestet und hat auch nicht geklappt. Ich nehme das originalbild aus dem Quellcode und auch ein mit Lightshot aufgezeichneter Screenshot.
 
Ist das Spiel f2p und wenn ja wo kann ich das spielen?

Würde es mal testen.
 
werd ich mir mal anschauen. Hab gedacht, dass Web scraping für einen anfänger einfacher wäre

Weiß nicht ich finde API requests einfacher.

Was du für den API request aufjedenfall brauchst ist das "cf_clearance" cookie.
Würde mir über Python 1x zu beginn die captcha challenge zeigen lassen und bei dem welcome screen dann den cf_clearence cookie snacken.

Danach kann eigentlich alles über CLI laufen.
 
finde python eigentlich super, aber gerade, wenn du jetzt erst damit beginnst, würde ich dir dafür javascript empfehlen. kannst du direkt in der dev konsole ausführen und hast somit auch keine probleme mit dem cloudflare cookie (falls das ein problem sein sollte).
kannst mit js auch direkt die funktionen ansprechen, die das spiel verwendet, würde hier imo mehr sinn machen.

wenn ich das problem jetzt richtig versetehe:
(falls du paar mehr screenshots hast, wäre das sicher gut...)

es gibt in dem "enemies nearby" grid 7 plätze, aber es sind nicht immer wirklich alle 7 plätze belegt?
was muss ich machen, dass ich nur auf die felder von 1-6 klicke, wenn nur 6 gegner angezeigt werden?

1721844563949.png
# hatte btw. kein block jetzt wirklich selenium zu starten, hab's nur kurz in js getestet.... ABER hier wäre der code mehr oder weniger:

schritt 1:
wir wollen gar nicht erst die einzelnen kleinen "buttons" mit xpaths hardcoden, wir wollen das ganze grid mit python auslesen und dann über alle objekte, die da drinnen sind, eine for each schleife laufen lassen.

Python:
grid_container = driver.find_element(By.XPATH, '//*[@id="game-container"]/div[1]/div[2]/div[1]/div[1]/div[2]/div/div[1]')

in dem grid_container sollten alle <button> elemente (monster) drinnen sein

Python:
monsters = grid_container.find_elements(By.TAG_NAME, 'button')

und jetzt noch for each über alle monster und fertig

Python:
for monster in monsters:
    monster.click()
    # hier jetzt noch auf "battle klicken...."
    time.sleep(1)


hier noch in js (mit selector anstatt xpath, weil ichs schöner finde):

JavaScript:
const buttons = document.querySelectorAll("div:nth-child(2) > div > div.grid.grid-cols-3.xs\\:grid-cols-4.sm\\:grid-cols-5.md\\:grid-cols-4.lg\\:grid-cols-5.xl\\:grid-cols-7.gap-x-3.gap-y-4 button");
buttons.forEach(button => {
    button.click();
});
1721846922883.png
 
  • Like
Reactions: zoyk
Danke schonmal für die Mühen die hier eingeflossen sind. Werde ich auch späteren Projekten dann mit Sicherheit umsetzen können.
Ich hab mein Anliegen tatsächlich etwas larifari erzählt, vermutlich weil ich eh schon ziemlich müde vom ganzen testen war.

Ich wollte nicht alle Monster angreifen, weil in meinem Sektor auch Monster sind, die einfach zu lange dauern um sie zu besiegen. Deswegen wollte ich die einzelnen paths oder Bilder raussuchen, um.nur ausgewählte Monster anzugreifen. Da die paths aber nur auf 1,2,3,4,... Buttons liegen und nicht auf die verschiedenen Monster selber, funktioniert das nicht und die bilderkennung funktioniert warum auch immer nicht. Also hab ich zusätzlich noch die Zeit gemessen, die ich brauche um dieses besagte Monster zu erledigen um dann mit 2-3 Sekunden delay das nächste Monster auszuwählen. Dieses Zeitmessen macht aber auch garkeinen Sinn, wenn die Monster auf den Zahlen immer random sind und nicht die Monster, sondern die Zahlen auf dem grid angegriffen werden. Ich hoffe das ist halbwegs verständlich.
Ich könnte einen schwierigkeitsgrad nach unten gehen und mit deiner Lösung alle Monster auf dem grid killen. Allerdings - woher weiss das Programm dann, wann der dight vorüber ist? Ich hab das mit nem eventtimer versucht und hat auch nicht so gut geklappt. Auch muss irgendwann mal geheilt werden, allerdings ist das Problem erstmal zu vernachlässigen.

Den cookie zu finden mit User agent usw hab ich bisher nicht geschafft, da bleib ich aber auch noch dran
 
Hab hier eben mal was für die API zusammengeschustert.
(Scheint auch ohne Cloudflare Token zu gehen...)


Python:
import browser_cookie3
import requests
import webbrowser

# Bin mir ziemlich sicher, dass Cookies nicht benötigt werden
# Jedenfalls spricht der geteste API Endpoint nicht auf Cookies an

cj = requests.utils.dict_from_cookiejar(browser_cookie3.brave()) # Musst du halt zu deinem lieblingsbrowser ändern

try:
    cloudflare_cookie = cj['cf_clearance']
except KeyError as e:
    print('No cloudflare cookie found, please login to the game first')
    webbrowser.open('https://web.idle-mmo.com/')
    exit()

print('[*] Found cloudflare cookie')
cookies = {
    'cf_clearance': cloudflare_cookie,
}

data = {
    'character_id': '134382'
}

headers = {
    # User-Agent muss zu dem Cookie passen, kein gesetzter User Agent wird ein 403 error schmeißen
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
    'Authorization': 'Bearer 0Vym4w0ULWNYU8eg1Yp1toNiriKxO6ozZGXQQLXO5xafItXVxKQMt8DY8O7L',
    'Accept': 'application/json',
    'Referer': 'https://web.idle-mmo.com/@logxndev'
}

url = 'https://web.idle-mmo.com/api/action/active?expires=1721936555&signature=7d60b607e1f173a208d1a94bde47101c8f11c75863026c5ecbc35dfcc8c012bf'

print('[*] Sending request (1/2) to active endpoint...', end='')
response = requests.post(url, headers=headers, json=data)

if response.status_code == 200:
    print('OK!')

    url = 'https://web.idle-mmo.com/api/character/information?expires=1721936555&signature=468c2f91658f2d5a25eb77f47d35ba033c3c8592c4014e1044e5e5622fecc4ed'
    
    print('[*] Sending request (2/2) to information endpoint...', end='')
    response = requests.post(url=url, headers=headers)

    if response.status_code == 200:
        print('OK!')

        json_response = response.json()
        print(json_response)

        print('[*] All good!')



1721852318148.gif
 
Hab hier eben mal was für die API zusammengeschustert.
(Scheint auch ohne Cloudflare Token zu gehen...)


Python:
import browser_cookie3
import requests
import webbrowser

# Bin mir ziemlich sicher, dass Cookies nicht benötigt werden
# Jedenfalls spricht der geteste API Endpoint nicht auf Cookies an

cj = requests.utils.dict_from_cookiejar(browser_cookie3.brave()) # Musst du halt zu deinem lieblingsbrowser ändern

try:
    cloudflare_cookie = cj['cf_clearance']
except KeyError as e:
    print('No cloudflare cookie found, please login to the game first')
    webbrowser.open('https://web.idle-mmo.com/')
    exit()

print('[*] Found cloudflare cookie')
cookies = {
    'cf_clearance': cloudflare_cookie,
}

data = {
    'character_id': '134382'
}

headers = {
    # User-Agent muss zu dem Cookie passen, kein gesetzter User Agent wird ein 403 error schmeißen
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
    'Authorization': 'Bearer 0Vym4w0ULWNYU8eg1Yp1toNiriKxO6ozZGXQQLXO5xafItXVxKQMt8DY8O7L',
    'Accept': 'application/json',
    'Referer': 'https://web.idle-mmo.com/@logxndev'
}

url = 'https://web.idle-mmo.com/api/action/active?expires=1721936555&signature=7d60b607e1f173a208d1a94bde47101c8f11c75863026c5ecbc35dfcc8c012bf'

print('[*] Sending request (1/2) to active endpoint...', end='')
response = requests.post(url, headers=headers, json=data)

if response.status_code == 200:
    print('OK!')

    url = 'https://web.idle-mmo.com/api/character/information?expires=1721936555&signature=468c2f91658f2d5a25eb77f47d35ba033c3c8592c4014e1044e5e5622fecc4ed'
   
    print('[*] Sending request (2/2) to information endpoint...', end='')
    response = requests.post(url=url, headers=headers)

    if response.status_code == 200:
        print('OK!')

        json_response = response.json()
        print(json_response)

        print('[*] All good!')



View attachment 662
Probier ich morgen direkt mal aus, hab jetzt aber erstmal nachtschicht
 
Danke schonmal für die Mühen die hier eingeflossen sind. Werde ich auch späteren Projekten dann mit Sicherheit umsetzen können.
Ich hab mein Anliegen tatsächlich etwas larifari erzählt, vermutlich weil ich eh schon ziemlich müde vom ganzen testen war.

Ich wollte nicht alle Monster angreifen, weil in meinem Sektor auch Monster sind, die einfach zu lange dauern um sie zu besiegen. Deswegen wollte ich die einzelnen paths oder Bilder raussuchen, um.nur ausgewählte Monster anzugreifen. Da die paths aber nur auf 1,2,3,4,... Buttons liegen und nicht auf die verschiedenen Monster selber, funktioniert das nicht und die bilderkennung funktioniert warum auch immer nicht. Also hab ich zusätzlich noch die Zeit gemessen, die ich brauche um dieses besagte Monster zu erledigen um dann mit 2-3 Sekunden delay das nächste Monster auszuwählen. Dieses Zeitmessen macht aber auch garkeinen Sinn, wenn die Monster auf den Zahlen immer random sind und nicht die Monster, sondern die Zahlen auf dem grid angegriffen werden. Ich hoffe das ist halbwegs verständlich.
Ich könnte einen schwierigkeitsgrad nach unten gehen und mit deiner Lösung alle Monster auf dem grid killen. Allerdings - woher weiss das Programm dann, wann der dight vorüber ist? Ich hab das mit nem eventtimer versucht und hat auch nicht so gut geklappt. Auch muss irgendwann mal geheilt werden, allerdings ist das Problem erstmal zu vernachlässigen.

Den cookie zu finden mit User agent usw hab ich bisher nicht geschafft, da bleib ich aber auch noch dran
in jedem <button> element gibt es auch einen <img> und jedes <img> hat ne source (src) und in der src steht der pfad zu den bildern.
den rest solltest du, hoffe ich, selber hinbekommen. einfach alle bilder pfade raus suchen -> checken, ob im aktuellen block in der for each loop als source das bild von z.B. der ente ist, und dann je nachdem attacken oder drüber skippen

für die cookies aus ner selenium session:
Python:
driver.get_cookies()

würde dir außerdem playwright anstatt selenium empfehlen
 
Last edited:
Probier ich morgen direkt mal aus, hab jetzt aber erstmal nachtschicht

Hab nochmal bisschen rumgefiddled und ein paar Hinweise wenn du die API ansprechen willst.

1) requests.Session() ist dein Freund
2) Die API erwartet immer einen korrekten Referer Header sonst gibts ein bad request response
3) Regex & BeautifulSoup werden deine Freunde, da die Endpoints hammer behindert gestored sind

Hier ist was zusammengewichstes für dynamic user creation: https://privatebin.net/?753089839009cb8e#8XQMerumGkJNWgy1FFWiNSoFw7YLfv1Q36u2RXXgZFGR

Sieht dann so aus wenn alles durchläuft.

1721858846109.png