Selenium点击下一页后无法定位翻页按钮元素问题求助
问题背景
需要爬取 FT equities results 页面 表格内的全量数据,页面底部配有「Next」按钮用于翻页,原有实现逻辑为循环读取当前页表格内容后点击下一页,初始代码如下:
stocks = [] count = 1 while(count <= pages): print("pages: {}".format(pages)) driver.execute_script("window.scrollTo(0, 800)") time.sleep(3) table = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//table")) ) rows = table.find_elements(By.TAG_NAME, "tr") driver.implicitly_wait(10) for row in rows: # Get the columns (all the column 2) col = row.find_elements(By.TAG_NAME, "td") if len(col) != 0: s = (col[0].text) sep = '\n' stripped = s.split(sep, 1)[0] if len(stocks) == 0: stocks.append(stripped) else: if stocks[-1] != stripped: stocks.append(stripped) driver.implicitly_wait(10) element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, "/html/body/div[3]/div[3]/section/div[2]/div/div/div/div[2]/div/button[8]")) ) driver.execute_script("window.scrollTo(0, 1200)") element.click() print(stocks) count+=1
故障表现
- 第一页内容读取正常,点击下一页进入第二页后,Selenium无法定位到后续页面的Next按钮
- 尝试直接从浏览器开发者工具复制CSS选择器、绝对XPath定位元素,均定位失败
- 使用
WebDriverWait显式等待元素可点击时,抛出等待超时异常 - 移除显式等待,直接通过绝对XPath查找元素(代码如下),抛出
NoSuchElementException元素不存在异常
driver.execute_script("window.scrollTo(0, 1200)") time.sleep(3) element = driver.find_element(By.XPATH, "/html/body/div[3]/div[3]/section/div[2]/div/div/div/div[2]/div/button[8]")
故障根因
- 定位方式完全失效:使用的是硬编码的绝对XPath,且写死了按钮序号
button[8]。第一页Next按钮刚好排在分页栏第8位,翻页后分页栏会动态新增/调整页码按钮位置,Next的排序序号会发生变化,绝对路径直接匹配不到目标元素 - 执行顺序错误:代码先等待元素可点击,再执行滚动操作。分页按钮初始不在浏览器视口范围内时,Selenium会判定元素不可交互、甚至无法识别元素
- DOM刷新判断缺失:点击翻页后没有等待旧页面DOM刷新,直接查找元素会命中第一页的缓存DOM,或是碰到分页栏还未渲染完成的空窗期
- 等待逻辑混乱:循环内反复调用
implicitly_wait设置全局隐式等待,和显式等待、固定sleep混用会互相干扰,拉长等待时长甚至触发异常判定
修复方案
- 替换绝对XPath为相对属性定位,通过按钮文本匹配Next按钮,不受分页按钮排序变化影响
- 调整执行顺序:先滚动到分页栏区域,再等待按钮可点击
- 新增翻页后的DOM刷新判断:等待上一页第一行的股票条目消失,确认新页内容加载完成
- 移除循环内重复的隐式等待设置,新增最后一页判断:检测Next按钮为禁用状态时自动终止循环,无需手动传入总页数
修复后的核心代码如下:
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait import time from selenium.common.exceptions import TimeoutException stocks = [] # 全局只设置一次隐式等待即可 driver.implicitly_wait(5) while True: # 滚动到表格区域 driver.execute_script("window.scrollTo(0, 800)") # 等待表格加载 table = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//table[contains(@class,'mod-ui-table')]")) ) rows = table.find_elements(By.TAG_NAME, "tr") # 读取当前页数据 page_first_stock = None for row in rows: col = row.find_elements(By.TAG_NAME, "td") if len(col) != 0: s = col[0].text stripped = s.split('\n', 1)[0] if not page_first_stock: page_first_stock = stripped if not stocks or stocks[-1] != stripped: stocks.append(stripped) # 先滚动到分页栏区域,再找Next按钮 driver.execute_script("window.scrollTo(0, document.body.scrollHeight)") time.sleep(0.5) try: next_btn = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, "//div[contains(@class,'o-pagination')]//button[normalize-space(text())='Next']")) ) except TimeoutException: # 找不到可点击的Next按钮说明到最后一页,退出循环 break next_btn.click() # 等待上一页的第一条股票消失,确认新页加载完成,避免命中旧DOM WebDriverWait(driver, 10).until( EC.staleness_of(table.find_element(By.XPATH, f".//td[contains(text(),'{page_first_stock}')]")) ) print(f"已爬取{len(stocks)}条股票数据") print(stocks)
注意:如果页面弹出cookie授权弹窗,需要先加一步点击关闭弹窗的逻辑,否则弹窗会遮挡分页按钮导致点击失败。
内容的提问来源于stack exchange,提问作者ictwinner
相关产品推荐
相关产品推荐

