VBA网页抓取:如何从同<tr>中获取目标球队的WIN统计数据
解决VBA+Selenium抓取NBA球队WIN数据的定位问题
原代码核心问题
- XPath相对定位错误:使用
//开头的XPath会从文档根节点重新搜索,而非当前元素的上下文。比如element.FindElementByXPath("//tbody/tr//span/..")会找到所有符合条件的元素,不是当前球队名称所在的父节点;后续//table/tbody/tr/td[6]也是全局查找第一行的第6个td,而非目标球队所在行。 - 遍历对象低效:遍历所有
<span>元素冗余,直接遍历表格行更高效且逻辑清晰。 - 等待机制不稳定:固定
driver.Wait容易因页面加载速度差异导致元素未就绪的运行时错误,应改用显式等待。
改进实现方案
直接遍历表格的每一行,匹配目标球队名称后,直接提取该行的WIN数据(第6个<td>),同时优化等待逻辑:
Sub nbaScrape_Stats() Dim driver As WebDriver Set driver = CreateObject("Selenium.WebDriver") Dim targetTeam As String targetTeam = ThisWorkbook.ActiveSheet.[C3].Value ' 目标球队名称 Dim xUrl As String xUrl = "https://www.nba.com/stats/teams/traditional" driver.Start "chrome" driver.Get xUrl, 10000 ' 显式等待同意按钮并点击,避免元素未加载 driver.WaitUntil ElementIsVisible(By.XPath("//*[@id='onetrust-accept-btn-handler']"), 10000) driver.FindElementByXPath("//*[@id='onetrust-accept-btn-handler']").Click ' 显式等待赛季下拉框选项并点击 driver.WaitUntil ElementIsVisible(By.XPath("//section[1]/div/div/div[4]/label/div/select/optgroup[1]/option[1]"), 10000) driver.FindElementByXPath("//section[1]/div/div/div[4]/label/div/select/optgroup[1]/option[1]").Click driver.Wait 1000 ' 等待表格刷新 ' 获取所有表格行 Dim teamRows As WebElements Set teamRows = driver.FindElementsByXPath("//tbody/tr") Dim row As WebElement Dim teamName As String Dim winData As String For Each row In teamRows ' 从当前行获取球队名称(相对定位,.//表示当前行上下文) teamName = row.FindElementByXPath(".//span[@class='team-name']").Text If teamName = targetTeam Then ' 获取当前行第6个td的文本(WIN数据) winData = row.FindElementByXPath(".//td[6]").Text Debug.Print targetTeam & "的WIN数据: " & winData, "-时间:-", Now() ' 写入Excel ThisWorkbook.ActiveSheet.Cells(1, 2).Value = winData Exit For ' 找到目标球队后退出循环,提升效率 End If Next row ThisWorkbook.ActiveSheet.UsedRange.Columns.AutoFit driver.Quit End Sub
关键优化点说明
- 相对XPath定位:使用
.//开头的XPath,确保在当前行的上下文内查找元素,避免全局搜索导致的定位错误。 - 显式等待:
WaitUntil ElementIsVisible等待元素加载完成后再操作,大幅降低运行时错误概率。 - 直接遍历行:仅遍历表格数据行,逻辑更清晰,减少不必要的元素遍历。
- 找到目标后退出循环:无需遍历所有行,提升执行效率。
备选方案:先存储所有数据再检索
如果需要多次查询不同球队,可先将所有球队数据存入字典,再检索目标球队:
Sub nbaScrape_Stats_StoreFirst() Dim driver As WebDriver Set driver = CreateObject("Selenium.WebDriver") Dim xUrl As String xUrl = "https://www.nba.com/stats/teams/traditional" driver.Start "chrome" driver.Get xUrl, 10000 ' 处理同意按钮和赛季选择 driver.WaitUntil ElementIsVisible(By.XPath("//*[@id='onetrust-accept-btn-handler']"), 10000) driver.FindElementByXPath("//*[@id='onetrust-accept-btn-handler']").Click driver.WaitUntil ElementIsVisible(By.XPath("//section[1]/div/div/div[4]/label/div/select/optgroup[1]/option[1]"), 10000) driver.FindElementByXPath("//section[1]/div/div/div[4]/label/div/select/optgroup[1]/option[1]").Click driver.Wait 1000 ' 创建字典存储球队名称和WIN数据 Dim teamStats As Object Set teamStats = CreateObject("Scripting.Dictionary") Dim teamRows As WebElements Set teamRows = driver.FindElementsByXPath("//tbody/tr") Dim row As WebElement Dim teamName As String Dim winData As String For Each row In teamRows teamName = row.FindElementByXPath(".//span[@class='team-name']").Text winData = row.FindElementByXPath(".//td[6]").Text teamStats(teamName) = winData Next row ' 检索目标球队数据 Dim targetTeam As String targetTeam = ThisWorkbook.ActiveSheet.[C3].Value If teamStats.Exists(targetTeam) Then Debug.Print targetTeam & "的WIN数据: " & teamStats(targetTeam), "-时间:-", Now() ThisWorkbook.ActiveSheet.Cells(1, 2).Value = teamStats(targetTeam) Else Debug.Print "未找到球队: " & targetTeam End If ThisWorkbook.ActiveSheet.UsedRange.Columns.AutoFit driver.Quit End Sub
内容的提问来源于stack exchange,提问作者xlmaster
相关产品推荐
相关产品推荐

