You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用HtmlAgilityPack解析HTML表格并将行数据赋值给自定义模型

问题原因分析

  • 第一个原因:浏览器渲染生成的tbody标签不存在于原始HTML源码中。你在浏览器开发者工具里复制的XPath包含tbody,但HtmlAgilityPack加载的是原始页面源码,多数维基百科的表格源码没有显式写tbody标签,导致你的行定位XPath本身就拿不到有效行数据,后续取值自然会出现异常。
  • 第二个原因:表格的第一行是表头行,子节点是th标签而非td标签,遍历到表头行时调用row.SelectNodes("td")自然返回null。
  • 第三个隐藏风险:单元格文本包含大量空白符、特殊符号(比如薪资里的$、逗号),直接调用DateTime.Parse、int.Parse大概率会抛出格式异常。

修正方案

1. 调整XPath定位

去掉XPath中的tbody节点,同时可以用更鲁棒的相对路径避免页面结构微调导致定位失效:

// 原错误XPath
"/html/body/div[3]/div[3]/div[5]/div[1]/table[1]/tbody/tr"
// 修正后XPath
"/html/body/div[3]/div[3]/div[5]/div[1]/table[1]/tr"
// 更稳定的相对定位(推荐)
"//table[@class='wikitable sortable jquery-tablesorter'][1]//tr"

2. 修正ParseTable方法逻辑

增加空值判断、表头过滤、文本清洗逻辑,修正后代码如下:

private static List<SuspensionModel> ParseTable(HtmlDocument htmlDocument, string xPath)
{
    var returnData = new List<SuspensionModel>();
    var rows = htmlDocument.DocumentNode.SelectNodes(xPath);
    // 先判断行集合是否为空
    if (rows == null || rows.Count == 0) return returnData;

    foreach (HtmlNode row in rows)
    {
        var cells = row.SelectNodes("td");
        // 过滤表头行、空行
        if (cells == null || cells.Count < 7) continue;

        // 清洗单元格文本:去除换行、多余空格、特殊符号
        var cleanedTexts = cells.Select(c => c.InnerText.Trim().Replace("\n", "").Replace("\t", "")).ToList();

        try
        {
            var susp = new SuspensionModel
            {
                IncidentDate = DateTime.Parse(cleanedTexts[0]),
                OffenderName = cleanedTexts[1],
                OffenderTeam = cleanedTexts[2],
                OffenseDesc = cleanedTexts[3],
                ActionDate = DateTime.Parse(cleanedTexts[4]),
                OffenseLength = cleanedTexts[5],
                // 清洗薪资字段:移除$、逗号后再转数字
                SalaryLoss = int.Parse(cleanedTexts[6].Replace("$", "").Replace(",", ""))
            };
            returnData.Add(susp);
        }
        catch (FormatException)
        {
            // 可在此处加日志,跳过格式异常的行
            continue;
        }
    }
    return returnData;
}

额外优化建议

  • 可以先调用HtmlNode.Descendants("table")拿到所有表格,再通过表格的特征(比如表头文本、类名)定位目标表格,比写死绝对XPath兼容性更好。
  • 日期解析可以指定格式,避免因为页面日期格式变化出现解析异常,比如DateTime.ParseExact(cleanedTexts[0], "MMMM d, yyyy", CultureInfo.InvariantCulture)。

内容的提问来源于stack exchange,提问作者dotnetdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 07:45:05