You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python脚本15分钟计时结束后未执行点击问题求助

问题

我编写了一个Python自动化脚本,预期功能如下:

  • 点击Spirit Attraction Potion 1 (Dose 1)
  • 设置15分钟后的结束时间
  • 在15分钟内随机点击Seren Stones,时间到后停止点击并切换至下一剂药水
  • 重复直至用完所有药剂,再切换至下一瓶药水循环执行

但运行日志显示:设置的结束时间为08:14:32,实际却在08:17:03才触发15分钟周期结束的操作,未按预期时间执行后续步骤。

运行日志

07:59:19 - Initial delay of 10 seconds before first click.
07:59:29 - Clicked on Spirit Attraction Potion 1 (Dose 1). Total clicks: 1
07:59:32 - Current time: 07:59:32, End time set to 08:14:32
07:59:32 - Clicked on Seren stone. Total clicks: 2
08:05:37 - Clicked on Seren stone. Total clicks: 3
08:11:52 - Clicked on Seren stone. Total clicks: 4
08:17:03 - 15 minutes interval completed for Potion 1, Dose 1.
08:17:04 - Clicked on Spirit Attraction Potion 1 (Dose 2). Total clicks: 5

脚本代码

import time
import random
import logging
import sys
import threading
import pyautogui
from pynput.keyboard import Listener, KeyCode

# Setup logging to output to the console
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(message)s',
    datefmt='%H:%M:%S',
    stream=sys.stdout
)

# Activation keys
START_STOP_KEY = KeyCode(char='-')
EXIT_KEY = KeyCode(char='+')

# Configuration
INITIAL_DELAY = 10  # Initial delay before the first click (seconds)
SEREN_CLICK_INTERVAL_MIN = 300  # Minimum interval between Seren stone clicks (seconds)
SEREN_CLICK_INTERVAL_MAX = 600  # Maximum interval between Seren stone clicks (seconds)
POST_CLICK_DELAY = 3  # Delay after each click (seconds)

# Global state
running = False
click_count = 0
click_thread = None
lock = threading.Lock()

def on_press(key):
    global running, click_thread
    try:
        if key == START_STOP_KEY:
            with lock:
                running = not running
            if running:
                logging.info("Script started.")
                click_thread = threading.Thread(target=click_loop)
                click_thread.start()
            else:
                logging.info("Script stopped.")
        elif key == EXIT_KEY:
            logging.info(f"Exiting script. Total clicks made: {click_count}")
            with lock:
                running = False
            if click_thread:
                click_thread.join()
            listener.stop()
    except Exception as e:
        logging.error(f"Error in on_press: {e}")

def click_loop():
    global click_count, running
    try:
        logging.info(f"Initial delay of {INITIAL_DELAY} seconds before first click.")
        time.sleep(INITIAL_DELAY)

        while running:
            try:
                perform_click_sequence()
            except Exception as e:
                logging.error(f"Error during click loop iteration: {e}")
                with lock:
                    running = False
    except Exception as e:
        logging.error(f"Error in click_loop: {e}")
        with lock:
            running = False

def perform_click_sequence():
    global click_count
    try:
        # Define coordinate ranges for each potion (example ranges)
        potion_coordinate_ranges = [
            ((1560, 1576), (838, 860)),  # Potion 1 (Row 3)
            ((1602, 1622), (838, 860)),  # Potion 2 (Row 3)
            ((1645, 1664), (838, 860)),  # Potion 3 (Row 3)
            ((1686, 1708), (838, 860)),  # Potion 4 (Row 3)
            ((1560, 1576), (874, 896)),  # Potion 1 (Row 4)
            ((1602, 1622), (874, 896)),  # Potion 2 (Row 4)
            ((1645, 1664), (874, 896)),  # Potion 3 (Row 4)
            ((1686, 1708), (874, 896)),  # Potion 4 (Row 4)
            ((1560, 1576), (908, 930)),  # Potion 1 (Row 5)
            ((1602, 1622), (908, 930)),  # Potion 2 (Row 5)
            ((1645, 1664), (908, 930)),  # Potion 3 (Row 5)
            ((1686, 1708), (908, 930)),  # Potion 4 (Row 5)
            ((1560, 1576), (946, 968)),  # Potion 1 (Row 6)
            ((1602, 1622), (946, 968)),  # Potion 2 (Row 6)
            ((1645, 1664), (946, 968)),  # Potion 3 (Row 6)
            ((1686, 1708), (946, 968)),  # Potion 4 (Row 6)
            # ... add coordinate ranges for all 26 potions
        ]

        for potion_number in range(1, 16):  # Loop through 16 potions
            for dose in range(4):  # Each potion has 4 doses
                if not running:
                    logging.info("Script is not running. Exiting click sequence.")
                    return

                # Get the coordinate range for the current potion
                x_range, y_range = potion_coordinate_ranges[potion_number - 1]
                
                # Generate random coordinates within the specified range
                x = random.randint(x_range[0], x_range[1])
                y = random.randint(y_range[0], y_range[1])
                
                # Click on the current potion
                click(f"Clicked on Spirit Attraction Potion {potion_number} (Dose {dose + 1})", x, y)

                time.sleep(POST_CLICK_DELAY)
                
                # Calculate the end time for the 15-minute interval
                end_time = time.time() + 15 * 60
                logging.info(f"Current time: {time.strftime('%H:%M:%S', time.localtime(time.time()))}, End time set to {time.strftime('%H:%M:%S', time.localtime(end_time))}")
                
                # Click Seren stones in a random sequence within the 15 minutes
                while time.time() < end_time:
                    if not running:
                        logging.info("Script is not running. Exiting click sequence.")
                        return
                    
                    click("Clicked on Seren stone", random.randint(780, 965), random.randint(335, 380))
                    
                    # Sleep for a random interval between clicks on Seren stone
                    time.sleep(random.uniform(SEREN_CLICK_INTERVAL_MIN, SEREN_CLICK_INTERVAL_MAX))
                    time.sleep(POST_CLICK_DELAY)

                logging.info(f"15 minutes interval completed for Potion {potion_number}, Dose {dose + 1}.")
    except Exception as e:
        logging.error(f"Error in perform_click_sequence: {e}")

def click(description, x, y):
    global click_count
    pyautogui.moveTo(x, y)
    pyautogui.click()
    click_count += 1
    logging.info(f"{description}. Total clicks: {click_count}")

try:
    with Listener(on_press=on_press) as listener:  # Start the keyboard listener
        logging.info("Listener started. Press '-' to start/stop and '+' to exit.")
        listener.join()  # Wait for the listener to stop
except Exception as e:
    logging.error(f"Error starting listener: {e}")

问题分析与修复方案

问题原因

核心问题在于Seren Stones的循环逻辑:每次点击后会进入一段300-600秒的长睡眠,再加3秒点击后延迟,但睡眠期间不会检查是否到达结束时间。比如最后一次点击Seren Stones是08:11:52,之后睡眠了约5分11秒+3秒延迟,醒来时已经远超设定的08:14:32结束时间,导致周期结束操作延迟触发。

修复方案

将长睡眠拆分为多次短睡眠(比如每次1秒),每次睡眠后立即检查是否到达结束时间或脚本是否停止,一旦满足条件就退出循环,确保15分钟到点时能及时停止操作。

修复后的代码

import time
import random
import logging
import sys
import threading
import pyautogui
from pynput.keyboard import Listener, KeyCode

# Setup logging to output to the console
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(message)s',
    datefmt='%H:%M:%S',
    stream=sys.stdout
)

# Activation keys
START_STOP_KEY = KeyCode(char='-')
EXIT_KEY = KeyCode(char='+')

# Configuration
INITIAL_DELAY = 10  # Initial delay before the first click (seconds)
SEREN_CLICK_INTERVAL_MIN = 300  # Minimum interval between Seren stone clicks (seconds)
SEREN_CLICK_INTERVAL_MAX = 600  # Maximum interval between Seren stone clicks (seconds)
POST_CLICK_DELAY = 3  # Delay after each click (seconds)
CHECK_INTERVAL = 1  # Interval to check end time during sleep (seconds)

# Global state
running = False
click_count = 0
click_thread = None
lock = threading.Lock()

def on_press(key):
    global running, click_thread
    try:
        if key == START_STOP_KEY:
            with lock:
                running = not running
            if running:
                logging.info("Script started.")
                click_thread = threading.Thread(target=click_loop)
                click_thread.start()
            else:
                logging.info("Script stopped.")
        elif key == EXIT_KEY:
            logging.info(f"Exiting script. Total clicks made: {click_count}")
            with lock:
                running = False
            if click_thread:
                click_thread.join()
            listener.stop()
    except Exception as e:
        logging.error(f"Error in on_press: {e}")

def click_loop():
    global click_count, running
    try:
        logging.info(f"Initial delay of {INITIAL_DELAY} seconds before first click.")
        time.sleep(INITIAL_DELAY)

        while running:
            try:
                perform_click_sequence()
            except Exception as e:
                logging.error(f"Error during click loop iteration: {e}")
                with lock:
                    running = False
    except Exception as e:
        logging.error(f"Error in click_loop: {e}")
        with lock:
            running = False

def perform_click_sequence():
    global click_count
    try:
        # Define coordinate ranges for each potion (example ranges)
        potion_coordinate_ranges = [
            ((1560, 1576), (838, 860)),  # Potion 1 (Row 3)
            ((1602, 1622), (838, 860)),  # Potion 2 (Row 3)
            ((1645, 1664), (838, 860)),  # Potion 3 (Row 3)
            ((1686, 1708), (838, 860)),  # Potion 4 (Row 3)
            ((1560, 1576), (874, 896)),  # Potion 1 (Row 4)
            ((1602, 1622), (874, 896)),  # Potion 2 (Row 4)
            ((1645, 1664), (874, 896)),  # Potion 3 (Row 4)
            ((1686, 1708), (874, 896)),  # Potion 4 (Row 4)
            ((1560, 1576), (908, 930)),  # Potion 1 (Row 5)
            ((1602, 1622), (908, 930)),  # Potion 2 (Row 5)
            ((1645, 1664), (908, 930)),  # Potion 3 (Row 5)
            ((1686, 1708), (908, 930)),  # Potion 4 (Row 5)
            ((1560, 1576), (946, 968)),  # Potion 1 (Row 6)
            ((1602, 1622), (946, 968)),  # Potion 2 (Row 6)
            ((1645, 1664), (946, 968)),  # Potion 3 (Row 6)
            ((1686, 1708), (946, 968)),  # Potion 4 (Row 6)
            # ... add coordinate ranges for all 26 potions
        ]

        for potion_number in range(1, 16):  # Loop through 16 potions
            for dose in range(4):  # Each potion has 4 doses
                if not running:
                    logging.info("Script is not running. Exiting click sequence.")
                    return

                # Get the coordinate range for the current potion
                x_range, y_range = potion_coordinate_ranges[potion_number - 1]
                
                # Generate random coordinates within the specified range
                x = random.randint(x_range[0], x_range[1])
                y = random.randint(y_range[0], y_range[1])
                
                # Click on the current potion
                click(f"Clicked on Spirit Attraction Potion {potion_number} (Dose {dose + 1})", x, y)

                time.sleep(POST_CLICK_DELAY)
                
                # Calculate the end time for the 15-minute interval
                end_time = time.time() + 15 * 60
                logging.info(f"Current time: {time.strftime('%H:%M:%S', time.localtime(time.time()))}, End time set to {time.strftime('%H:%M:%S', time.localtime(end_time))}")
                
                # Click Seren stones in a random sequence within the 15 minutes
                while time.time() < end_time:
                    if not running:
                        logging.info("Script is not running. Exiting click sequence.")
                        return
                    
                    click("Clicked on Seren stone", random.randint(780, 965), random.randint(335, 380))
                    
                    # Calculate random sleep duration and split into small chunks
                    sleep_duration = random.uniform(SEREN_CLICK_INTERVAL_MIN, SEREN_CLICK_INTERVAL_MAX)
                    slept = 0
                    while slept < sleep_duration and time.time() < end_time and running:
                        time.sleep(CHECK_INTERVAL)
                        slept += CHECK_INTERVAL
                    
                    # Only apply post-click delay if we haven't reached end time yet
                    if time.time() < end_time and running:
                        time.sleep(POST_CLICK_DELAY)

                logging.info(f"15 minutes interval completed for Potion {potion_number}, Dose {dose + 1}.")
    except Exception as e:
        logging.error(f"Error in perform_click_sequence: {e}")

def click(description, x, y):
    global click_count
    pyautogui.moveTo(x, y)
    pyautogui.click()
    click_count += 1
    logging.info(f"{description}. Total clicks: {click_count}")

try:
    with Listener(on_press=on_press) as listener:  # Start the keyboard listener
        logging.info("Listener started. Press '-' to start/stop and '+' to exit.")
        listener.join()  # Wait for the listener to stop
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 00:16:57