开发Selenium Python井字棋机器人时遇AttributeError:字符串无click方法
解决Selenium中数组存储XPATH后无法点击元素的问题
问题背景
我用Selenium Python开发在线井字棋机器人,已将棋盘格子的XPATH提取并存储到变量中。机器人逻辑为随机点击格子,但执行代码行squares[random_square].click()时触发AttributeError,原因是数组中存储的是字符串类型的XPATH,而字符串没有click()方法。
之前我通过以下方式正常获取可点击元素并点击:
pickSquare = WebDriverWait(load_browser, 10).until(EC.element_to_be_clickable(By.XPATH, Tags.someSquare)) pickSquare.click()
但将所有XPATH存入数组后,不清楚如何对数组中的XPATH应用By和EC。当前代码如下:
class TestCase_PlayGame(): URL = "http://localhost:3000" @pytest.fixture def load_browser(self, browser): browser.get(self.URL) yield browser def test_playGame(self, load_browser): squares = [Tags.square1,Tags.square2,Tags.square3, Tags.square4,Tags.square5,Tags.square6, Tags.square7,Tags.square8,Tags.square9] clickedSquares = [] random_square = randint(0,8) time.sleep(10) for i in clickedSquares: if i == random_square: self.test_playGame() else: clickedSquares.append(random_square) squares[random_square].click()
更新的回溯信息:
self = <TestCases.TestCase_PlayGame.TestCase_PlayGame object at 0x000001DA3F4139D0> load_browser = <selenium.webdriver.firefox.webdriver.WebDriver (session="324ff7dc-195c-4bdf-9ceb-84bf978dfc66")> def test_playGame(self, load_browser): squares = [Tags.square1,Tags.square2,Tags.square3, Tags.square4,Tags.square5,Tags.square6, Tags.square7,Tags.square8,Tags.square9] clickedSquares = [] random_square = randint(0,8) time.sleep(10) for i in clickedSquares: if i == random_square: self.test_playTTT() else: clickedSquares.append(random_square) > squares[random_square].click() E AttributeError: 'str' object has no attribute 'click' TestCases\TestCase_PlayGame.py:52: AttributeError
核心问题分析
squares数组存储的是字符串类型的XPATH,并非Selenium的WebElement对象,直接调用.click()必然报错。- 现有循环逻辑无效:
clickedSquares初始为空列表,for i in clickedSquares不会执行;递归调用测试方法self.test_playGame()会导致重复初始化,逻辑混乱。
解决方案
步骤1:通过XPATH获取WebElement对象
对数组中选中的XPATH,使用WebDriverWait和EC.element_to_be_clickable获取可点击的元素对象,再调用click()方法。
步骤2:修正随机选格逻辑
筛选未被点击过的格子索引,避免重复点击;去掉错误的递归调用,改用循环实现多次点击逻辑。
修正后的完整代码
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By import random import time import pytest class TestCase_PlayGame(): URL = "http://localhost:3000" @pytest.fixture def load_browser(self, browser): browser.get(self.URL) yield browser def test_playGame(self, load_browser): # 存储所有格子的XPATH路径 square_xpaths = [Tags.square1, Tags.square2, Tags.square3, Tags.square4, Tags.square5, Tags.square6, Tags.square7, Tags.square8, Tags.square9] clicked_indices = [] # 示例:循环点击5次未选中的格子,可根据需求调整次数或改为游戏结束条件 for _ in range(5): # 筛选出未被点击过的格子索引 available_indices = [idx for idx in range(9) if idx not in clicked_indices] if not available_indices: break # 无可用格子时退出循环 # 随机选择一个可用格子 random_idx = random.choice(available_indices) clicked_indices.append(random_idx) # 通过XPATH获取可点击元素并执行点击 target_xpath = square_xpaths[random_idx] target_square = WebDriverWait(load_browser, 10).until( EC.element_to_be_clickable((By.XPATH, target_xpath)) ) target_square.click() time.sleep(1) # 可选:等待页面响应,避免操作过快导致异常
关键说明
- 将原数组名
squares改为square_xpaths,明确存储的是路径字符串,提升代码可读性。 - 使用列表推导式
available_indices动态筛选未点击的格子,确保每次选择的都是可用格子。 - 用
random.choice()替代randint,直接从可用索引中选取,避免选到已点击的格子。 - 移除无效的空循环和错误的递归调用,改用更清晰的循环逻辑控制点击次数。
内容的提问来源于stack exchange,提问作者Trevor
相关产品推荐
相关产品推荐

