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

基于子元素信息修改父元素Class属性的Selenium页面自动化问题咨询

嘿,我来帮你搞定这个Selenium的问题!你遇到的相同ID按钮无法激活的情况,其实可以通过两种思路解决:要么直接模拟用户点击切换状态(更符合真实操作),要么手动修改DOM的class属性。另外我也会帮你把获取价格的逻辑整合进去。

方案一:直接点击按钮的父容器(推荐)

页面上的这些按钮应该是Bootstrap的btn-group-toggle组件,这类组件通常是点击外层的div.btn来切换选中状态,自动把class改成btn active,而不是直接点击input元素。你可以通过子元素的ID来定位对应的父div,然后点击它:

# 处理RCPE选项(Yes)
rcpe_yes_div = driver.find_element_by_xpath('//div[contains(@class, "btn") and input[@id="quote_equine_owner_hasSubscribedRcpe_0"]]')
rcpe_yes_div.click()

# 处理RCPE选项(No)
rcpe_no_div = driver.find_element_by_xpath('//div[contains(@class, "btn") and input[@id="quote_equine_owner_hasSubscribedRcpe_1"]]')
rcpe_no_div.click()

# 同理处理兽医费用订阅选项
sub_yes_div = driver.find_element_by_xpath('//div[contains(@class, "btn") and input[@id="quote_equine_owner_subscribeVeterinaryCharge_0"]]')
sub_yes_div.click()

sub_no_div = driver.find_element_by_xpath('//div[contains(@class, "btn") and input[@id="quote_equine_owner_subscribeVeterinaryCharge_1"]]')
sub_no_div.click()

这种方法不需要手动修改DOM,完全模拟用户操作,更稳定,也不容易出问题。

方案二:手动修改父元素的Class属性

如果你确实需要修改class属性,可以通过子元素找到父div,然后用Selenium的execute_script来修改:

# 找到Yes选项的input元素
rcpe_yes_input = driver.find_element_by_id('quote_equine_owner_hasSubscribedRcpe_0')
# 获取它的直接父div
parent_div = rcpe_yes_input.find_element_by_xpath('..')
# 执行JS修改class属性
driver.execute_script("arguments[0].className = 'btn active';", parent_div)

这个方法直接修改DOM,适合一些特殊场景,但不如模拟点击自然。

整合到你的循环逻辑,获取最终价格

现在把这些逻辑整合到你的循环里,遍历所有年份、价格、Yes/No选项,然后提取价格。假设价格元素有特定的class或ID(你需要根据实际页面调整定位),完整代码如下:

import time
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import csv

driver = webdriver.Chrome()  # 初始化你的浏览器驱动
driver.get('https://equi.generali.fr/devis-en-ligne-proprietaire-d-un-equide')

# 先处理Cookie按钮(用显式等待替代sleep,更可靠)
WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.ID, 'popin_tc_privacy_button'))
).click()

# 获取年份和价格选项(过滤空值)
input_year = driver.find_element_by_id('quote_equine_owner_equineBirthYear')
options_year = [
    option.get_attribute("value") 
    for option in input_year.find_elements_by_tag_name('option') 
    if option.get_attribute("value")
]

input_gear = driver.find_element_by_id('quote_equine_owner_equineValue')
options_gear = [
    option.get_attribute("value") 
    for option in input_gear.find_elements_by_tag_name('option') 
    if option.get_attribute("value")
]

# 定义所有需要遍历的Yes/No选项组合
rcpe_options = [
    ('yes', 'quote_equine_owner_hasSubscribedRcpe_0'),
    ('no', 'quote_equine_owner_hasSubscribedRcpe_1')
]
sub_options = [
    ('yes', 'quote_equine_owner_subscribeVeterinaryCharge_0'),
    ('no', 'quote_equine_owner_subscribeVeterinaryCharge_1')
]

# 存储结果的列表
price_results = []

# 遍历所有组合
for year in options_year:
    input_year.send_keys(year)
    time.sleep(2)
    
    if int(year) > 2000:
        for price in options_gear:
            input_gear.send_keys(price)
            time.sleep(2)
            
            # 遍历RCPE的Yes/No
            for rcpe_text, rcpe_id in rcpe_options:
                # 点击对应的按钮容器
                rcpe_div = driver.find_element_by_xpath(f'//div[contains(@class, "btn") and input[@id="{rcpe_id}"]]')
                rcpe_div.click()
                time.sleep(1)
                
                # 遍历兽医订阅的Yes/No
                for sub_text, sub_id in sub_options:
                    sub_div = driver.find_element_by_xpath(f'//div[contains(@class, "btn") and input[@id="{sub_id}"]]')
                    sub_div.click()
                    time.sleep(2)
                    
                    # 获取最终价格(这里需要根据实际页面调整元素定位,示例用价格类名)
                    try:
                        final_price = WebDriverWait(driver, 10).until(
                            EC.presence_of_element_located((By.XPATH, '//span[contains(@class, "price-amount")]'))
                        ).text
                        # 存储结果
                        price_results.append({
                            'year': year,
                            'horse_value': price,
                            'rcpe': rcpe_text,
                            'veterinary_sub': sub_text,
                            'final_price': final_price
                        })
                        print(f"获取到价格:年份{year},马匹价值{price},RCPE{rcpe_text},兽医订阅{sub_text},价格{final_price}")
                    except Exception as e:
                        print(f"获取价格失败:{e}")

# 把结果保存到CSV文件
with open('horse_insurance_prices.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames=['year', 'horse_value', 'rcpe', 'veterinary_sub', 'final_price'])
    writer.writeheader()
    writer.writerows(price_results)

driver.quit()

注意事项

  • 你需要根据页面实际的价格元素定位调整XPath,比如用浏览器开发者工具查看价格对应的HTML标签和属性。
  • 推荐用WebDriverWait显式等待替代固定的time.sleep,可以避免页面加载慢导致的元素找不到问题。
  • 如果页面有动态刷新,可能需要在点击选项后等待价格元素更新完成再提取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:32:45