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

Python Selenium:滚动页面时点击所有表格行以抓取数据

解决Grainger表格行点击展开及数据抓取问题

问题根源分析

你的代码无法实现表格行点击展开的核心问题如下:

  • 直接对find_elements(By.TAG_NAME, 'tr')返回的元素列表调用click(),属于语法错误,必须遍历每个<tr>元素逐个执行点击操作。
  • 点击行后未等待展开内容加载完成,导致后续无法抓取目标数据。
  • 部分元素选择器不准确(比如SKU的选择器缺少类名前缀.)。
  • 滚动页面的方式无法确保所有行都处于可交互状态。

修改后的完整代码

import undetected_chromedriver as uc
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
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 StaleElementReferenceException
import pandas as pd
import time


def scrape_page_data():
    # 等待产品列表容器加载完成
    container = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.CLASS_NAME, 'pl'))
    )
    
    # 获取所有表格行(排除表头行)
    rows = WebDriverWait(container, 10).until(
        EC.presence_of_all_elements_located((By.TAG_NAME, 'tr'))
    )
    # 跳过表头,只处理数据行
    data_rows = rows[1:] if len(rows) > 1 else rows

    prod_num = []
    prod_price = []
    prod_desc = []

    for index, row in enumerate(data_rows):
        try:
            # 滚动到当前行,确保元素可点击
            driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", row)
            time.sleep(0.5)
            
            # 等待行元素可点击并执行点击
            WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable(row)
            ).click()
            
            # 等待展开内容加载完成
            time.sleep(1)
            # 显式等待展开区域的元素出现
            WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, '.sku-value__value'))
            )

            # 抓取当前行的厂商型号(MFR Model)
            sku = row.find_element(By.CSS_SELECTOR, '.sku-value__value').text
            prod_num.append(sku)

            # 抓取当前行的价格
            price = row.find_element(By.CSS_SELECTOR, '.rbqU0E.lVwVq5').text
            prod_price.append(price)

            # 抓取当前行的描述
            desc = row.find_element(By.CSS_SELECTOR, '.fUWsxn._3ihaM4').text
            prod_desc.append(desc)

        except StaleElementReferenceException:
            # 处理元素过时异常,重新获取当前行
            data_rows = WebDriverWait(container, 10).until(
                EC.presence_of_all_elements_located((By.TAG_NAME, 'tr'))
            )[1:]
            row = data_rows[index]
            # 重新执行点击和抓取逻辑
            driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", row)
            WebDriverWait(driver, 10).until(EC.element_to_be_clickable(row)).click()
            time.sleep(1)
            sku = row.find_element(By.CSS_SELECTOR, '.sku-value__value').text
            prod_num.append(sku)
            price = row.find_element(By.CSS_SELECTOR, '.rbqU0E.lVwVq5').text
            prod_price.append(price)
            desc = row.find_element(By.CSS_SELECTOR, '.fUWsxn._3ihaM4').text
            prod_desc.append(desc)
        except Exception as e:
            # 处理其他异常,避免程序中断
            print(f"处理第{index+1}行时出错: {str(e)}")
            prod_num.append('')
            prod_price.append('')
            prod_desc.append('')

    return prod_num, prod_price, prod_desc

def pagination(url, pages=1):
    prod_num = []
    prod_price = []
    prod_desc = []

    page_num = 0
    for i in range(1, pages + 1):
        driver.get(f"{url}?offset={page_num}")
        print(f"正在抓取第{i}页...")
        
        current_skus, current_prices, current_descs = scrape_page_data()
        
        prod_num.extend(current_skus)
        prod_price.extend(current_prices)
        prod_desc.extend(current_descs)

        print(f"第{i}页抓取完成,共{len(current_skus)}条数据")
        print(f"累计数据量: 型号{len(prod_num)}条,价格{len(prod_price)}条,描述{len(prod_desc)}条")

        page_num += 24
        time.sleep(2)

    return prod_num, prod_price, prod_desc


# 初始化浏览器
website = 'https://www.grainger.com/category/adhesives-sealants-and-tape/patching-repairing-compounds/wall-repair-patching?categoryIndex=2'
options = Options()
driver = uc.Chrome(options=options)

# 执行抓取
prod_num, prod_price, prod_desc = pagination(website, pages=1)

# 保存数据到CSV
df = pd.DataFrame({
    '厂商型号(MFR Model)': prod_num,
    '价格': prod_price,
    '描述': prod_desc
})
df.to_csv('grainger_wall_repair.csv', index=False, encoding='utf-8-sig')
print("数据已保存到grainger_wall_repair.csv")
print(df.head())

# 关闭浏览器
driver.quit()

关键修改说明

  • 遍历表格行:循环处理每个数据行,跳过表头行,确保每一行都被点击展开。
  • 元素交互保障:使用scrollIntoView将当前行滚动到可视区域,避免元素不可点击;通过element_to_be_clickable等待元素处于可交互状态。
  • 异常处理:捕获StaleElementReferenceException(元素过时异常),重新获取元素后继续执行,避免程序崩溃。
  • 数据抓取优化:点击后等待展开内容加载,确保目标元素存在后再抓取,避免空值;同时直接从当前行定位子元素,确保数据对应关系正确。
  • 选择器修正:将SKU的选择器修正为.sku-value__value(添加类名前缀.),确保定位准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 19:50:01