
本文详解如何通过 selenium 精准定位并获取动态加载的 html 表格中所有球员行元素,重点解决因页面未就绪或 xpath 不精确导致 `find_elements` 返回空列表的问题。
在使用 Selenium 抓取 Basketball-Reference 等结构化体育数据网站时,一个常见误区是:直接调用 find_elements_by_xpath 而未等待目标内容加载完成,或使用过于宽泛/不稳定的 XPath 表达式(如 //tr/td[@data-stat="player"]),导致匹配失败或返回空列表。
例如,原始代码:
players_list = driver.find_elements_by_xpath('//tr/td[@data-stat="player"]')
print(len(players_list)) # 常常输出 0,即使页面上明显存在该列问题根源有二:
-
时机问题:
是异步渲染或依赖 JS 动态注入的,页面 GET 完成后 DOM 可能尚未就绪;
- 定位粒度问题://tr/td[@data-stat="player"] 匹配的是
单元格,而非整行 ;而 find_elements 若返回的是分散的 ,不仅语义不清,还可能因表格嵌套、隐藏行(如注释、分隔符)干扰匹配结果。 ✅ 正确做法是:
- 优先利用唯一 ID 定位父容器(如 //table[@id='roster']);
- 以
行为单位抓取,再从中提取所需 或文本,逻辑更健壮; - 强制显式等待(WebDriverWait),确保目标表格已存在于 DOM 中。
以下是兼容 Selenium 4.17+ 的推荐实现(find_element_by_* 已全面弃用):
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 driver = webdriver.Firefox() driver.get("https://www.php.cn/link/7f5667890e56de28cb734293df7d2c73") # 等待 roster 表格整体加载完成(比等待单个 td 更可靠) wait = WebDriverWait(driver, 10) wait.until(EC.presence_of_element_located((By.ID, "roster"))) # 定位 roster 表格的所有数据行(排除 和空行) players_rows = driver.find_elements(By.XPATH, "//table[@id='roster']/tbody/tr[.//td[@data-stat='player']]") print(f"成功找到 {len(players_rows)} 名球员") # 示例:提取每位球员姓名(位于 data-stat="player" 的 td 内) for i, row in enumerate(players_rows[:3]): # 打印前3名验证 name_cell = row.find_element(By.XPATH, ".//td[@data-stat='player']") print(f"{i+1}. {name_cell.text.strip()}")⚠️ 注意事项:
- 避免使用 time.sleep() 替代 WebDriverWait —— 效率低且不可靠;
- //table[@id='roster']/tbody/tr 默认包含表头行(
中无 data-stat),因此建议加过滤条件 [.//td[@data-stat='player']] 确保只取有效数据行; - 若需处理分页或懒加载内容,请额外检查是否存在“Show More”按钮并触发点击;
- 生产环境建议添加异常处理(如 TimeoutException, NoSuchElementException)提升鲁棒性。
通过结合精准 XPath + 显式等待 + 语义化元素层级选择,即可稳定获取动态表格中的完整球员列表,彻底规避“长度为 0”的陷阱。
- 定位粒度问题://tr/td[@data-stat="player"] 匹配的是










