Hayk
Hayk

Reputation: 159

Action Chain in loop works only once(Selenium/Python)

I'm trying to implement a cookie clicker bot. Cookie clicker it's just a stupid simple game, where you can click on the cookie to earn more cookies. You can take a look at that masterpiece here. The bot should just open the page, and click on the cookie 4000 times, but it clicks only one time.

import time

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait    
from selenium.webdriver.common.action_chains import ActionChains

PATH = "C:\Program Files (x86)\chromedriver.exe"
driver = webdriver.Chrome(PATH)
driver.get("https://orteil.dashnet.org/cookieclicker/")

driver.implicitly_wait(10)

cookie = driver.find_element(By.ID, "bigCookie")

actions = ActionChains(driver)
actions.click(cookie)

for i in range(4000):
    actions.perform()

I see these messages in the console. What is wrong with me my code? errors

Upvotes: 2

Views: 1709

Answers (3)

Koushik
Koushik

Reputation: 1

You should use reset_actions() which clears actions that are already stored locally and on the remote end.

You can add some time delay while performing mouse movement operations.

for i in range(4000):
  actions.reset_actions()
  actions.click(cookie)
  actions.perform()

Upvotes: 0

Nate W
Nate W

Reputation: 320

Here was my solution to the coding challenge. Note that just as @Prophet suggested, what I ended up doing was putting my code inside of the for loop.

Initial Imports and Declarations

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import ActionChains

def getCount(count):
    try:
        v = int(str(count).split(" ")[0])
        return v
    except:
        return 0

#strings
url = "https://orteil.dashnet.org/cookieclicker/"
english = "langSelect-EN"
bigCookie = "bigCookie"
cookieCount = "cookies"

Load the Page & Click "English"

options = Options()
options.page_load_strategy = 'normal'
driver = webdriver.Chrome(options=options)
driver.implicitly_wait(10)
driver.get(url)

print("Looking for language button")
language = driver.find_element(By.ID, english)
language.click()

The Guts of the Code

for i in range(5000): 
    try:
        print("Cycle " + str(i))
        cookie = driver.find_element(By.ID, bigCookie)
        counter = driver.find_element(By.ID, cookieCount)
        cookies = getCount(counter.text)
        items = [driver.find_element(By.ID, "productPrice" + str(i)) for i in range(2, -1, -1) ]
        
        # I tried this both ways, and it clicks significantly faster if I don't use "ActionChains"
        # actions = ActionChains(driver)
        # actions.move_to_element(cookie)
        # actions.click(cookie)
        # actions.perform()
        cookie.click()

        for item in items:
            price = getCount(item.text)
            if price > 0 and price <= cookies:
                actions = ActionChains(driver)
                actions.move_to_element(item)
                actions.click()
                actions.perform()
    except:
        print(f"Cycle {i} Failed :-(")

Hope this helps!

Upvotes: 0

Prophet
Prophet

Reputation: 33361

What you trying to do here is to load the gun one time and then to press on trigger several times in a loop... To do what you wish you should slightly change your code as following:

actions = ActionChains(driver)

for i in range(4000):
    actions.click(cookie)
    actions.perform()

BTW I guess this code will still not work since after the first click on the cookie element even if it will appear again it will be a NEW, ANOTHER element even if it could be located with the same locator.
So trying to click it again will cause StaleElementReferenceException.
To make this work you will have to locate the cookie element again each time, as following:

actions = ActionChains(driver)

for i in range(4000):
    cookie = wait.until(EC.visibility_of_element_located((By.ID, "bigCookie")))
    actions.click(cookie)
    actions.perform()

Upvotes: 1

Related Questions