如何在Python Selenium中分页并保存页面HTML?遇循环及元素过期异常
解决分页遍历HTML保存的Selenium问题
我来帮你搞定这两个分页循环的问题,先拆解下每个方案的问题根源,再给你修复后的可用代码:
问题根源分析
第一种方案的问题
- 漏掉了第一页的HTML保存:直接进入循环点击下一页,初始页面的内容根本没存入列表
- 循环内未重新定位元素:页面刷新后,之前定位的
search元素已经和DOM脱离,你判断的其实是旧元素的状态,导致末页时无法正确触发退出条件 - 判断逻辑不准确:前端是通过
disabled属性+自定义class控制禁用状态,单纯用is_enabled()不一定能准确识别禁用状态
第二种方案的问题
- 仅在循环前定位一次元素:点击下一页后页面DOM重新渲染,原来的
search元素就变成了“过时引用”,自然抛出StaleElementReferenceException
修复后的解决方案
核心思路是:每次循环重新定位元素、先存第一页、用更准确的末页判断逻辑,具体代码如下:
from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from bs4 import BeautifulSoup import time # 存储HTML页面的列表 news_list = [] # 第一步:先保存第一页的HTML wait = WebDriverWait(driver, 10) # 等待当前页码元素加载完成,确保页面已就绪 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "li[data-testid='current-page-item']"))) first_html = driver.page_source soup_first = BeautifulSoup(first_html, "html.parser") news_list.append(soup_first) # 第二步:循环处理后续页面 while True: try: # 每次循环都重新定位下一页箭头(最后一个li元素) next_page_btn = wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/div/div/div[2]/div[2]/div/ol/li[5]'))) # 精准判断是否为末页:同时检查disabled属性和专属禁用class is_last_page = next_page_btn.get_attribute("disabled") is not None and "fDeSdf" in next_page_btn.get_attribute("class") if is_last_page: # 到达末页,退出循环 break # 点击下一页 next_page_btn.click() # 推荐用显式等待替代固定sleep,这里先保留sleep方便理解 time.sleep(5) # 保存当前页面HTML current_html = driver.page_source soup_current = BeautifulSoup(current_html, "html.parser") news_list.append(soup_current) except Exception as e: print(f"分页处理出错: {str(e)}") break
关键优化点
- 先存第一页:避免漏掉初始页面的内容
- 循环内重新定位元素:彻底解决
StaleElementReferenceException,因为每次页面刷新后都重新获取最新的元素引用 - 精准末页判断:结合
disabled属性和前端自定义的禁用class,比单纯用is_enabled()更适配页面的实际逻辑 - 异常捕获:防止循环中出现意外错误导致程序直接崩溃
另外,建议把固定的time.sleep(5)替换成显式等待,比如等待当前页码更新,这样更高效稳定:
# 替换time.sleep(5)的代码 # 等待旧的当前页码元素失效(说明页面开始刷新) old_current_page = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "li[data-testid='current-page-item']"))) wait.until(EC.staleness_of(old_current_page)) # 等待新的当前页码元素出现(说明页面加载完成) wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "li[data-testid='current-page-item']")))
这样可以确保页面完全加载后再获取HTML,避免捕获到未渲染完成的内容。
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

