如何使用Selenium/Python展开网站多层嵌套下拉箭头提取目标内容
多层嵌套下拉框爬虫效率优化方案
现有代码的可优化问题梳理
你当前采用的硬编码循环定位下拉元素、固定时长休眠、逐层手动点击展开的写法,存在几个明显的效率和稳定性问题:
- 写死
range(0,13)的循环试错逻辑,一旦页面分组数量超出13个就会漏抓,页面结构微调也容易直接失效 - 固定0.5秒的休眠策略,页面加载快时浪费时间,加载慢时又会因等待不足拿到空白内容
- 逐层级手动定位产品、评级入口的方式,元素多的时候操作链路长,速度慢
具体优化实现步骤
1. 替换硬编码定位逻辑,全覆盖匹配可展开下拉箭头
去掉写死循环范围的试错代码,直接匹配所有Product Group层级的可展开箭头,不管页面内有多少个分组都能完整覆盖:
element_list = [] # 匹配所有带分组属性的展开箭头,过滤隐藏不可见的节点 dropdown_toggles = driver.find_elements(By.CSS_SELECTOR, "a[href*='grouping_'] span") for toggle in dropdown_toggles: if toggle.is_displayed(): element_list.append(toggle)
2. 用动态等待替换固定休眠,减少无效等待
把固定时长的sleep(0.5)换成元素可交互的显式等待逻辑:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import ElementNotInteractableException for toggle in element_list: try: # 等元素真正可点击时再操作,不做盲等 WebDriverWait(driver, 2).until(EC.element_to_be_clickable(toggle)) webdriver.ActionChains(driver).move_to_element(toggle).click().perform() time.sleep(0.2) # 仅留极短时间给DOM完成渲染 except ElementNotInteractableException: continue
注意:原代码遍历元素列表时从索引1开始,会跳过第一个产品分组,没有特殊业务需求的话直接全量遍历列表元素即可,避免漏抓内容。
3. 批量触发子层级展开,跳过逐一点击的低效流程
等上层所有Product Group全部展开后,不需要逐个点产品再找Protection Ratings入口,直接全局匹配所有Protection Ratings的可点击节点,一次循环全部点开:
# 全局匹配文本为Protection Ratings的节点,不需要逐层数XPATH路径 rating_toggles = driver.find_elements(By.XPATH, "//*[contains(text(), 'Protection Ratings')]") for toggle in rating_toggles: try: WebDriverWait(driver,1).until(EC.element_to_be_clickable(toggle)) toggle.click() except: continue
如果需要进一步压缩运行时间,可以直接用JS修改DOM的折叠状态,跳过鼠标模拟的交互开销:
# 直接修改元素类名触发展开,不依赖鼠标事件 driver.execute_script(""" document.querySelectorAll('.collapsed, .expandable:not(.expanded)').forEach(el => { el.classList.remove('collapsed') el.classList.add('expanded') }) """)
4. 关联提取三类目标字段,避免数据错位
所有内容渲染完成后,不要分开单独抓取产品名、评级描述、目标数值,顺着产品节点的父子关联关系绑定字段,避免全局遍历导致的顺序错位:
product_titles = driver.find_elements(By.CSS_SELECTOR, '.seat-title') scraped_result = [] for title_el in product_titles: product_name = title_el.text.strip() # 从当前产品标题往下找相邻的评级内容,不需要全局搜索 rating_desc = title_el.find_element(By.XPATH, "./following::*[contains(@class, 'rating-description')][1]").text.strip() target_value = title_el.find_element(By.XPATH, "./following::*[contains(@class, 'rating-score')][1]").text.strip() scraped_result.append({ "产品名称": product_name, "评级描述": rating_desc, "目标数值": target_value })
版本适配提醒
你之前使用的find_elements_by_css_selector是Selenium 3的旧版API,目前Selenium 4已经将这类方法废弃,统一替换成find_elements(By.XXX)的写法即可消除版本弃用告警。
内容的提问来源于stack exchange,提问作者Allan Bond
相关产品推荐
相关产品推荐

