如何用Selenium WebDriver/Python点击无超链接楼层并遍历获取信息
解决Selenium点击楼层元素失效的问题
问题背景
作为网页爬取新手,想要从指定页面获取可用公寓信息,计划用Selenium依次点击每个楼层提取动态数据(公寓编号、租金等),但当前代码的点击操作无法生效。
给出的楼层元素HTML结构:
<li id="floor-item-42349" role="option" aria-selected="false" aria-label="Floor 21 selected, 1 of 19 stories. 2 Units available." tabindex="-1" class="css-1ge3v7g-itemStyles"> <span class="primary-font css-1an6fko-floorStyles">21</span> <span class="css-1cygnfi-countStyles"> <span class="css-1gmg8q9-numberStyles">2</span> <span class="css-1c0jwqn-unitLabelStyles">Units</span> </span> </li>
当前失效的代码:
floors = wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "#floor-vertical-select > li "))) for floor in floors: if floor.text != "0": print("Floor: " + floor.text) floor.click()
失效原因分析
- 元素不可交互:楼层元素的
tabindex="-1"意味着它默认不可被聚焦,普通的click()方法可能因为元素无法接收焦点而失效。 - Stale元素问题:点击楼层后页面动态更新,之前获取的
floors列表可能变成过期元素,后续点击会报错。 - 元素未完全在视口内:楼层列表可能较长,部分元素不在当前视口,直接点击会失败。
- 选择器判断逻辑问题:
floor.text != "0"的判断不准确,楼层文本是楼层号(比如21),可用单元数在子元素里,这个条件会过滤掉所有非0的楼层号,逻辑错误。
另外,aria-label是无障碍辅助标签,用于给屏幕阅读器提供描述,不是点击失效的关键,但可以用来提取楼层的额外信息(比如可用单元数)。
解决方案
修改后的代码示例
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time # 初始化浏览器 driver = webdriver.Chrome() driver.get("https://sightmap.com/embed/rx1p8y12vd6") wait = WebDriverWait(driver, 10) # 等待楼层选择器加载完成 wait.until(EC.presence_of_element_located((By.ID, "floor-vertical-select"))) # 获取楼层总数,避免循环中元素过期 floor_total = len(wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "#floor-vertical-select li")))) for index in range(floor_total): # 每次循环重新定位所有楼层,防止元素过期 floors = wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "#floor-vertical-select li"))) current_floor = floors[index] # 提取楼层号和可用单元数 floor_num = current_floor.find_element(By.CSS_SELECTOR, ".css-1an6fko-floorStyles").text available_units = current_floor.find_element(By.CSS_SELECTOR, ".css-1gmg8q9-numberStyles").text # 只处理有可用单元的楼层 if available_units != "0": print(f"楼层: {floor_num},可用单元数: {available_units}") # 滚动到当前楼层元素,确保在视口内 driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", current_floor) time.sleep(0.5) # 给页面滚动留缓冲时间 # 使用JavaScript点击,绕过元素不可聚焦的限制 driver.execute_script("arguments[0].click();", current_floor) # 等待当前楼层的公寓信息加载完成 time.sleep(1) # 提取当前楼层的公寓信息 units = wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "[class*='unitStyles']"))) for unit in units: # 从aria-label提取公寓编号、户型等信息 unit_info = unit.get_attribute("aria-label") # 提取租金(如果存在) rent_elem = unit.find_elements(By.CSS_SELECTOR, "[class*='priceStyles']") rent = rent_elem[0].text if rent_elem else "暂无租金信息" print(f" 公寓详情: {unit_info},租金: {rent}") # 关闭浏览器 driver.quit()
关键优化点
- 重新定位元素:每次循环重新获取楼层列表,避免因页面更新导致的StaleElementReferenceException。
- JS点击替代普通点击:
driver.execute_script("arguments[0].click();", element)可以绕过元素tabindex="-1"的不可聚焦限制,确保点击生效。 - 滚动到元素可见:用
scrollIntoView将元素滚动到视口中央,避免因元素被遮挡导致点击失败。 - 修正判断逻辑:通过子元素提取可用单元数,只处理有可用公寓的楼层,避免无效点击。
- 利用aria-label提取信息:单元元素的
aria-label通常包含公寓编号、户型等详细内容,可以直接提取使用。
内容的提问来源于stack exchange,提问作者user2634937
相关产品推荐
相关产品推荐

