
本文介绍一种实用的 selenium 技术方案,用于动态获取 power bi 嵌入报表中惰性加载的下拉菜单(如“municipio”)全部可见选项,通过模拟键盘导航与元素轮询实现稳定抓取。
本文介绍一种实用的 selenium 技术方案,用于动态获取 power bi 嵌入报表中惰性加载的下拉菜单(如“municipio”)全部可见选项,通过模拟键盘导航与元素轮询实现稳定抓取。
在 Power BI 嵌入式报表中,许多下拉筛选器(如 MUNICIPIO)采用虚拟滚动(virtual scrolling)或按需渲染(lazy rendering)机制:初始 HTML 仅包含当前可视区域的少量选项,其余项在用户滚动或聚焦时才动态注入 dom。这导致直接使用 find_elements(By.XPATH, “//div[@class=’slicerItemContainer’]”) 等常规方式无法一次性获取全部选项——这也是你遇到“只有部分选项出现在 HTML 中”的根本原因。
针对此类动态下拉菜单,推荐采用 键盘驱动 + 状态轮询法:先触发下拉展开,再持续发送 Keys.DOWN 键模拟向下导航,逐项读取当前高亮项的文本,并利用 DOM 元素的唯一性(如 class=”slicerItemContainer setFocusRing” 或 data-row-index)识别焦点变化,直至循环回到首项(闭环检测),从而完整捕获所有可选值。
以下为完整、健壮的实现代码(含显式等待与容错处理):
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time driver = webdriver.Chrome() # 推荐使用 webdriver-manager 自动管理驱动版本 wait = WebDriverWait(driver, 20) # 1. 访问 Power BI 报表(注意 URL 中 ?r= 参数需完整) url = "https://app.powerbi.com/view?r=eyJrIjoiYjQ1NTA2OTYtYTNkMi00ZTM4LWI2ODUtZjE0MTdhODg2OWU3IiwidCI6IjU2YzFlMmZiLTg3YzEtNGRlMC1hNmFjLWQwNTY2YzA4Y2U2NiJ9" driver.get(url) # 2. 定位并点击下拉触发器(aria-label 是 Power BI 的标准标识) dropdown_trigger = wait.until( EC.element_to_be_clickable((By.XPATH, "//div[@aria-label='MUNICIPIO']")) ) dropdown_trigger.click() # 3. 等待首个可聚焦项出现(Power BI 通常用 'slicerItemContainer setFocusRing' 标识当前焦点) first_item = wait.until( EC.visibility_of_element_located((By.XPATH, "//div[contains(@class, 'slicerItemContainer') and contains(@class, 'setFocusRing')]")) ) options = [] prev_text = None # 4. 循环导航并收集选项(闭环检测:当新文本等于首个已存文本时终止) while True: # 强制等待确保 UI 更新完成(关键!避免读取旧状态) time.sleep(0.15) # 重新定位当前焦点元素(因 DOM 可能重绘) current = wait.until( EC.visibility_of_element_located((By.XPATH, "//div[contains(@class, 'slicerItemContainer') and contains(@class, 'setFocusRing')]")) ) current_text = current.text.strip() # 防止空文本或重复添加 if current_text and current_text not in options: options.append(current_text) # 发送 DOWN 键,移动焦点到下一项 current.send_keys(Keys.DOWN) # 检测是否循环回起点(闭环条件) if prev_text == current_text and len(options) > 1: break prev_text = current_text print(f"成功提取 {len(options)} 个 MUNICIPIO 选项:") for i, opt in enumerate(options, 1): print(f"{i}. {opt}") # 后续可对 options 进行遍历操作,例如: # for option in options: # dropdown_trigger.click() # # 再次定位并点击目标选项(需更精确的 XPath,如 text() 匹配)
✅ 关键注意事项:
- time.sleep(0.1–0.2) 不可省略:Power BI 渲染存在微小延迟,过快读取会导致 current.text 返回上一项内容或空字符串;
- 始终 re-locate 当前焦点元素:DOM 节点可能被销毁重建,直接复用旧 WebElement 对象会引发 StaleElementReferenceException;
- 优先使用 contains(@class, ‘xxx’) 而非精确匹配 @class=’…’:Power BI 动态添加 class(如 setFocusRing、isselected),类名组合易变;
- 闭环判断建议增强:除文本比对外,还可结合 data-row-index 属性(若存在)或计数上限(如预估最大 500 项)防止无限循环;
- 生产环境建议封装为函数,并加入异常处理(如超时、元素不可见、网络中断等)。
该方法绕过了 Power BI 私有 API 的限制,纯前端自动化,兼容大多数嵌入式报表场景。掌握此模式后,亦可迁移至其他采用虚拟滚动的 Web 组件(如 Ant Design Select、AG Grid 下拉等)。