HTMLAgilityPack无法识别首个元素:NBA赛程爬取异常问题
解决ESPN NBA赛程爬取的异常问题
问题根源
ESPN的NBA赛程页面依赖JavaScript动态渲染内容,HtmlWeb直接加载的是服务器返回的原始HTML,并非浏览器渲染后的完整DOM结构。这就导致你获取到的内容缺失了动态生成的当日赛程,反而拿到了预加载的次日内容,同时日期与表格不匹配。
解决方案1:使用无头浏览器获取渲染后页面
推荐用.NET生态下的PuppeteerSharp(无头浏览器库),它能模拟浏览器执行JS,获取完整的渲染后HTML。
- 先安装NuGet包:
Install-Package PuppeteerSharp
- 示例代码:
using PuppeteerSharp; using HtmlAgilityPack; // 下载浏览器(首次运行需要) var browserFetcher = new BrowserFetcher(); await browserFetcher.DownloadAsync(); // 启动无头浏览器 using var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true }); using var page = await browser.NewPageAsync(); // 等待页面完全加载(直到网络空闲) await page.GoToAsync("https://www.espn.com/nba/schedule", new NavigationOptions { WaitUntil = WaitUntilNavigation.Networkidle2 }); // 获取渲染后的完整HTML var renderedHtml = await page.GetContentAsync(); // 用HtmlAgilityPack解析 var doc = new HtmlDocument(); doc.LoadHtml(renderedHtml); // 遍历每个赛程容器 var scheduleContainers = doc.DocumentNode.SelectNodes("//div[contains(@class, 'ScheduleTables')]"); if (scheduleContainers != null) { foreach (var container in scheduleContainers) { // 提取日期 var dateElement = container.SelectSingleNode("./div[not(contains(@class, 'Table'))]"); var date = dateElement?.InnerText.Trim() ?? "未识别日期"; // 提取对应表格tbody var tableBody = container.SelectSingleNode("./table[contains(@class, 'Table')]/tbody"); if (tableBody != null) { // 处理表格行数据 var rows = tableBody.SelectNodes("./tr"); if (rows != null) { foreach (var row in rows) { // 示例:提取对阵球队和时间 var teamNodes = row.SelectNodes("./td[contains(@class, 'team')]"); var timeNode = row.SelectSingleNode("./td[contains(@class, 'time')]"); if (teamNodes != null && teamNodes.Count == 2 && timeNode != null) { var homeTeam = teamNodes[0].InnerText.Trim(); var awayTeam = teamNodes[1].InnerText.Trim(); var gameTime = timeNode.InnerText.Trim(); // 后续业务逻辑处理... } } } } } }
解决方案2:直接请求API接口(更稳定)
分析浏览器的网络请求,找到ESPN返回赛程数据的API端点,直接请求JSON格式的数据,比解析HTML更可靠:
- 打开浏览器开发者工具(F12),切换到「网络」标签;
- 刷新赛程页面,筛选
XHR/Fetch请求,找到返回赛程数据的接口(通常包含schedule或calendar关键字); - 用
HttpClient直接请求该接口,解析返回的JSON数据即可。
注意事项
- 避免频繁请求,ESPN有反爬机制,可设置请求间隔或添加
User-Agent等请求头模拟浏览器; - API接口可能会随网站更新变化,需要定期验证。
内容的提问来源于stack exchange,提问作者Łukasz Michalski
相关产品推荐
相关产品推荐

