使用Selenium无法点击Twitter评论按钮的技术求助
Twitter机器人评论按钮定位问题解决方法
问题描述
我正在开发一款Twitter机器人,目前遇到无法点击评论按钮的问题。无论复制使用哪种XPATH,都会出现元素找不到的错误。当前用于定位评论按钮的代码为:
comment_button = driver.find_element(By.XPATH, '//*[@id="id__pm1tufstyp"]/div[1]/div')
以下是完整代码(运行时需填入邮箱、用户名和密码):
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.keys import Keys import time import random URL = "https://twitter.com/" user_agents = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", ] service = Service() options = webdriver.ChromeOptions() options.add_argument(f"user-agent={random.choice(user_agents)}") driver = webdriver.Chrome(service=service, options=options) driver.get(URL) time.sleep(random.uniform(3, 5)) accept_cookies = driver.find_element(By.XPATH, '//*[@id="layers"]/div/div/div/div/div/div[2]/div[1]/div') accept_cookies.click() sign_in = driver.find_element(By.XPATH, '//*[@id="react-root"]/div/div/div[2]/main/div/div/div[1]/div[1]/div/div[3]/div[5]/a/div') sign_in.click() time.sleep(2) email = driver.find_element(By.XPATH, '//*[@id="layers"]/div[2]/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div/div/div/div[5]/label/div/div[2]/div/input') email.click() email.send_keys('YOUR EMAIL') time.sleep(1) next_button_1 = driver.find_element(By.XPATH, '//*[@id="layers"]/div[2]/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div/div/div/div[6]/div') next_button_1.click() time.sleep(1) #Twitter sometimes asks for username sometimes doesn't try: user_name = driver.find_element(By.XPATH, '//*[@id="layers"]/div/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div[1]/div/div[2]/label/div/div[2]/div/input') user_name.click() user_name.send_keys('YOUR USERNAME') next_button_2 = driver.find_element(By.XPATH, '//*[@id="layers"]/div[2]/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div[2]/div/div/div/div/div') next_button_2.click() time.sleep(1) except: print("Username input field not found. Twitter may not have requested it.") password = driver.find_element(By.XPATH, '//*[@id="layers"]/div[2]/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div[1]/div/div/div[3]/div/label/div/div[2]/div[1]/input') password.click() password.send_keys('YOUR PASSWORD') sing_in_button = driver.find_element(By.XPATH, '//*[@id="layers"]/div[2]/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div[2]/div/div[1]/div/div/div/div') sing_in_button.click() time.sleep(5) search_button = driver.find_element(By.XPATH, '//*[@id="react-root"]/div/div/div[2]/header/div/div/div/div[1]/div[2]/nav/a[2]/div') search_button.click() time.sleep(1) search_bar = driver.find_element(By.XPATH, '//*[@id="react-root"]/div/div/div[2]/main/div/div/div/div/div/div[1]/div[1]/div/div/div/div/div/div[1]/div[2]/div/div/div/form/div[1]/div/div/div/label/div[2]/div/input') search_bar.click() search_bar.send_keys('elon musk') search_bar.send_keys(Keys.ENTER) time.sleep(3) driver.execute_script(f"window.scrollTo(0, 300);") time.sleep(2) comment_button = driver.find_element(By.XPATH, '//*[@id="id__pm1tufstyp"]/div[1]/div') comment_button.click() time.sleep(1) reply_message = driver.find_element(By.XPATH, '//*[@id="layers"]/div[2]/div/div/div/div/div/div[2]/div[2]/div/div/div/div[3]/div[2]/div[2]/div/div/div/div[1]/div[2]/div/div/div/div/div/div/div/div/div/div/div/label/div[1]/div/div/div/div/div/div[2]/div/div/div/div') reply_message.click() reply_message.send_keys('hello') reply = driver.find_element(By.XPATH, '//*[@id="layers"]/div[2]/div/div/div/div/div/div[2]/div[2]/div/div/div/div[3]/div[2]/div[2]/div/div/div/div[2]/div[2]/div/div/div/div[2]') reply.click() time.sleep(15)
问题原因
你使用的XPATH依赖动态生成的元素ID(id__pm1tufstyp),Twitter基于React渲染的页面会随机生成这类ID,每次刷新或会话都会变化,因此无法稳定定位元素。
解决方法
1. 用稳定属性定位评论按钮
Twitter的交互元素通常带有aria-label或data-testid属性,这些属性是专为功能测试设计的,不会随页面刷新变化。定位第一条推文的评论按钮可以用以下方式:
# XPATH方式 comment_button = driver.find_element(By.XPATH, '//article[@data-testid="tweet"]//button[@aria-label="回复"]') # CSS选择器方式(更简洁) comment_button = driver.find_element(By.CSS_SELECTOR, 'article[data-testid="tweet"] button[aria-label="回复"]')
2. 替换硬等待为显式等待
time.sleep()是不可靠的等待方式,页面加载速度波动会导致元素未就绪就执行操作。改用WebDriverWait等待元素可点击,提升代码稳定性:
首先在代码开头导入相关模块:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC
然后替换原有的等待逻辑,比如定位评论按钮时:
# 等待10秒,直到评论按钮可点击 comment_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'article[data-testid="tweet"] button[aria-label="回复"]')) ) comment_button.click()
3. 修正回复框和发送按钮的定位
同样,回复框和发送按钮也需要用稳定属性定位:
# 等待回复输入框加载并输入内容 reply_box = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'div[data-testid="tweetTextarea_0"]')) ) reply_box.click() reply_box.send_keys('hello') # 定位并点击发送按钮 send_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-testid="tweetButton"]')) ) send_button.click()
完整优化后的代码片段
替换原代码中从driver.execute_script(...)到最后的部分:
driver.execute_script(f"window.scrollTo(0, 300);") # 等待评论按钮可点击并点击 comment_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'article[data-testid="tweet"] button[aria-label="回复"]')) ) comment_button.click() # 等待回复框并输入内容 reply_box = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'div[data-testid="tweetTextarea_0"]')) ) reply_box.click() reply_box.send_keys('hello') # 等待发送按钮并点击 send_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-testid="tweetButton"]')) ) send_button.click() time.sleep(5) driver.quit()
额外建议
- 避免使用基于层级结构的长XPATH,这类路径容易因页面布局变化失效
- 优先使用
data-testid、aria-label这类专为测试设计的属性定位元素 - 所有元素操作前都用显式等待,替代
time.sleep(),提升代码稳定性
内容的提问来源于stack exchange,提问作者SolidOpt
相关产品推荐
相关产品推荐

