You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Python的Selenium点击按钮后获取动态表格数据?

如何使用Python的Selenium点击按钮后获取动态表格数据?

问题详情

我正在做一个个人项目,用Python和Selenium爬取中小企业厅数据库里的动态数据。网页里的企业信息是卡片形式展示的,点击卡片里的按钮会动态加载出包含费用明细的表格。不过遇到了麻烦:按钮能被检测到并且成功点击(已经用打印语句确认过),但动态表格的数据却没出现在driver.page_source里,哪怕我已经等了表格加载的时间。

遇到的问题

  • 点击按钮后,对应的表格数据始终拿不到
  • driver.page_source里找不到预期的动态加载表格内容

我尝试过的方法

  • 用打印语句确认按钮确实被检测到并成功点击了
  • 手动在浏览器里点击按钮,确认表格是能正常加载出来的
  • WebDriverWait设置了足够长的等待时间,等表格加载
  • 查看浏览器开发者工具的网络活动,试图找到相关的API请求

我的猜想

  • 页面可能在点击按钮后会发送额外的网络请求来获取表格数据,但Selenium没捕获到更新后的内容
  • 按钮点击可能没正确触发浏览器里的必要事件

解决方案

一、如何可靠获取点击按钮后的动态表格数据?

这里有几个可以调整的点,帮你更稳定地拿到表格:

  1. 更精准的等待条件
    你之前用EC.presence_of_element_located((By.TAG_NAME, "table"))等待所有table元素的出现,但页面里可能本来就有其他表格,导致等待提前结束。最好改成等待当前卡片内的表格,并且等待表格可见而不是仅仅存在(存在只是DOM里有,可见才是渲染完成):
# 等待当前卡片内的表格可见
WebDriverWait(card, 10).until(EC.visibility_of_element_located((By.TAG_NAME, "table")))
  1. 直接通过Selenium获取表格元素,而非依赖page_source
    有时候driver.page_source不会实时更新最新的DOM内容,不如直接从卡片里定位表格元素,获取它的outerHTML
# 直接从当前卡片里找表格
table = card.find_element(By.TAG_NAME, "table")
if table:
    # 获取表格的HTML内容
    return format_table_data(table.get_attribute('outerHTML'))
  1. 优化按钮的定位逻辑
    你的XPATH用了contains(text(), '{side}側'),如果按钮文本里有空格或者换行,可能匹配不到。可以用normalize-space()处理文本的空格问题:
button = card.find_element(
    By.XPATH,
    f".//a[contains(@class, '{button_color}') and contains(normalize-space(text()), '{side}側')]"
)
  1. 确认按钮点击的触发方式
    虽然你用了JS点击,但有时候JS点击可能不如原生的button.click()可靠(比如有些页面会监听鼠标点击事件),可以先试试原生点击,如果不行再回退到JS点击:
# 先尝试原生点击
button.click()
# 如果不行再用JS点击
# driver.execute_script("arguments[0].click();", button)

二、如果表格数据是通过API请求获取的,怎么直接拿到数据?

如果通过浏览器开发者工具发现表格数据是通过API接口返回的,那直接调用API会比用Selenium更高效:

  1. 找到目标API
    打开浏览器开发者工具的「网络」标签,筛选「XHR/fetch」类型的请求,然后点击按钮,观察新出现的请求,找到返回表格数据的那个API,记录它的请求URL、请求方法(GET/POST)和必要的参数(比如企业ID、费用类型等)。

  2. 直接调用API获取数据
    requests库发送请求,注意要携带必要的Cookie和请求头(因为页面可能需要会话验证),可以从Selenium的driver里获取当前会话的Cookie:

# 从driver里获取Cookie,转换成requests需要的格式
cookies = {cookie['name']: cookie['value'] for cookie in driver.get_cookies()}
# 发送API请求
response = requests.get(api_url, cookies=cookies, headers=headers)
# 解析返回的JSON数据(假设API返回JSON)
table_data = response.json()

这样你就能直接拿到结构化的数据,不用再处理HTML解析的问题了。

修改后的核心函数示例

def get_fee_details_optimized(card, fee_type, side):
    try:
        # Determine button color based on fee_type
        if fee_type == "FA":
            button_color = "bg-yellow-500"
        elif fee_type == "仲介":
            button_color = "bg-green-500"
        else:
            raise ValueError(f"Invalid fee_type: {fee_type}")

        # 优化XPATH,处理文本空格问题
        button = card.find_element(
            By.XPATH,
            f".//a[contains(@class, '{button_color}') and contains(normalize-space(text()), '{side}側')]"
        )
        print(button)

        # 先尝试原生点击,不行再用JS
        try:
            button.click()
            print(f"Clicked Button: {fee_type} {side}側 using native click.")
        except:
            driver.execute_script("arguments[0].click();", button)
            print(f"Clicked Button: {fee_type} {side}側 using JavaScript.")

        # 等待当前卡片内的表格可见
        WebDriverWait(card, 10).until(EC.visibility_of_element_located((By.TAG_NAME, "table")))

        # 直接从卡片获取表格的HTML
        table = card.find_element(By.TAG_NAME, "table")
        if table:
            return format_table_data(table.get_attribute('outerHTML'))
        else:
            print(f"No table found for {fee_type} {side}側")
            return "No table found"

    except Exception as e:
        print(f"Error retrieving fee details for {fee_type} {side}側: {e}")
        return "N/A"

备注:内容来源于stack exchange,提问作者Kazato Yoshida

火山引擎 最新活动