悠悠楠杉
使用.NET解析HTML文档:HtmlAgilityPack实战指南
真正有价值的内容往往藏在 <body> 的某个区块中,可能是 <article>、.content 类,或是特定 ID 的容器。以常见的新闻页面为例,假设正文包裹在一个 class 为 post-body 的 div 中:
csharp
var bodyNode = doc.DocumentNode.SelectSingleNode("//div[@class='post-body']");
if (bodyNode != null)
{
// 清理干扰元素,如广告、脚注
foreach (var script in bodyNode.SelectNodes(".//script|.//style|.//nav"))
{
script.Remove();
}
string content = bodyNode.InnerText
.Replace("\n", "")
.Replace("\r", "")
.Trim();
// 截取前1000字作为摘要
if (content.Length > 1000)
content = content.Substring(0, 1000);
}
上述代码不仅提取文本,还主动清理了常见的非正文节点,确保输出干净。对于动态生成的内容,可能需要结合 Selenium 等工具先渲染页面再交由 HtmlAgilityPack 处理。
处理复杂结构与容错设计
实际项目中,HTML 结构千变万化。同一个站点不同页面的布局可能略有差异,跨站采集更是挑战重重。为此,建议采用“多路径尝试 + 默认兜底”的策略:
csharp
string[] contentXPaths = {
"//article",
"//div[@class='content']",
"//main",
"//div[contains(@class, 'post')]"
};
HtmlNode contentNode = null;
foreach (var path in contentXPaths)
{
contentNode = doc.DocumentNode.SelectSingleNode(path);
if (contentNode != null) break;
}
if (contentNode == null)
contentNode = doc.DocumentNode.SelectSingleNode("//body"); // 最后防线
这种柔性匹配机制显著提升了程序鲁棒性。
总结与思考
HtmlAgilityPack 不只是一个 HTML 解析器,更是一种思维方式的转变——从字符串匹配转向结构化数据提取。它让 .NET 开发者能以优雅的方式应对复杂的网页解析任务。当然,在使用过程中也需遵守网站的 robots.txt 协议,合理控制请求频率,尊重服务器资源。技术本身无善恶,关键在于如何运用。
