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

Selenium Python多页爬取问题:循环无法终止及数据获取异常

解决Selenium多页数据提取的循环终止与最后一页数据问题

问题根源

  1. 循环无法自动终止:到达最后一页时,"Next page"按钮仍存在但处于禁用状态,原代码依赖element_to_be_clickable()的超时异常终止循环,但该条件会持续等待元素变为可点击状态,导致循环卡住;部分场景下禁用按钮不会触发超时异常,循环会无限执行。
  2. 最后一页数据需手动终止才能获取:循环卡住后,程序无法执行到后续的数据合并与导出步骤,只有手动终止程序时,已收集的数据才会被保留。

修复方案

核心调整点

  • 直接检查下一页按钮的禁用状态(通过disabled属性或类名),而非依赖点击异常
  • 确保循环结束后合并所有数据,避免丢失已收集的内容
  • 添加页面切换后的等待逻辑,确保新页面加载完成

修改后的完整代码

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import pandas as pd

opts = webdriver.ChromeOptions()
opts.headless = True
driver = webdriver.Chrome(ChromeDriverManager().install())
base_url = "XYZ"
driver.maximize_window()
driver.get(base_url)
driver.set_page_load_timeout(50)

# 等待页面初始元素加载
WebDriverWait(driver, 50).until(EC.presence_of_element_located((By.ID, 'all-my-groups')))
# 输入筛选条件
driver.find_element(By.XPATH, '//*[@id="sim-issueListContent"]/div[1]/div/div/div[2]/div[1]/span/div/input').send_keys('No Stock')

dfs = []
page_counter = 0
wait = WebDriverWait(driver, 30)

while True:
    # 等待当前页数据元素可见
    wait.until(EC.visibility_of_all_elements_located((By.XPATH, "//div[contains(@class, 'alias-wrapper sim-ellipsis sim-list--shortId')]")))
    
    # 提取当前页数据
    cards = driver.find_elements(By.XPATH, "//div[contains(@class, 'alias-wrapper sim-ellipsis sim-list--shortId')]")
    sims = [[card.text] for card in cards]
    dfs.append(pd.DataFrame(sims))
    
    print(f"已收集第 {page_counter} 页数据")
    page_counter += 1
    
    # 检查下一页按钮状态
    try:
        next_btn = wait.until(EC.presence_of_element_located((By.XPATH, '//button[@aria-label="Next page"]')))
        
        # 判断按钮是否禁用:优先检查disabled属性,若无效则检查span类名
        if next_btn.get_attribute("disabled") is not None:
            print("已到达最后一页,终止循环")
            break
        
        # 若按钮依赖span类名判断禁用,替换为以下代码(根据实际禁用类调整)
        # span_element = next_btn.find_element(By.TAG_NAME, "span")
        # if "awsui_variant-disabled" in span_element.get_attribute("class"):
        #     print("已到达最后一页,终止循环")
        #     break
        
        # 点击下一页并等待页面切换
        next_btn.click()
        wait.until(EC.staleness_of(cards[0]))  # 等待当前页元素失效,确保新页面加载
    except TimeoutException:
        print("未找到下一页按钮或超时,终止循环")
        break

# 合并所有数据并输出/保存
final_df = pd.concat(dfs, ignore_index=True)
print(f"所有数据收集完成,共 {len(final_df)} 条记录")
# 可选:保存到本地文件
# final_df.to_csv("no_stock_data.csv", index=False)

driver.quit()

关键修改说明

  1. 禁用状态判断:通过get_attribute("disabled")直接检查按钮是否禁用,比等待点击异常更可靠;若页面用类名标识禁用状态,可切换为检查span元素的类名。
  2. 页面切换等待:使用EC.staleness_of()等待当前页元素失效,确保新页面完全加载后再进行下一轮数据提取。
  3. 数据合并:循环结束后用pd.concat()合并所有页面的DataFrame,确保数据能正常输出或保存,无需手动终止程序。
  4. 代码优化:统一创建WebDriverWait实例,用列表推导式简化数据收集逻辑,改用driver.quit()一次性关闭驱动与窗口。

内容的提问来源于stack exchange,提问作者Siva

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 21:01:40