网页爬取中如何用if替代try/catch规避ArgumentNullException
异常根因
你的链式调用里有三处未判空的风险点,任意一处触发就会抛出空异常:
document.DocumentNode.SelectNodes("//td")当页面无任何<td>节点时,HtmlAgilityPack的该方法返回null而非空集合,直接对null调用Where()会触发空引用类错误- 遍历td节点时,
x.Attributes["title"]遇到无title属性的td节点时返回null,直接访问.Value会触发错误 - 即使title属性存在,其
Value可能为null字符串,直接调用.Contains("Log.html")会抛出ArgumentNullException
正确实现逻辑
不要直接写嵌套链式判空,把每一层可能为null的节点都做判空兜底,同时避免重复调用SelectNodes浪费性能:
// 第一步:先获取所有td节点,空结果直接兜底为空集合,避免null引用 var allTdNodes = document.DocumentNode.SelectNodes("//td") ?? Enumerable.Empty<HtmlNode>(); // 第二步:带全量判空的筛选逻辑,符合条件的节点直接存下来,无需重复查询 var matchedNodes = allTdNodes // 先筛选存在title属性的节点 .Where(td => td.Attributes["title"] != null) // 再筛选title值非空、且包含目标字符串的节点 .Where(td => !string.IsNullOrEmpty(td.Attributes["title"].Value) && td.Attributes["title"].Value.Contains("Log.html")) .ToArray(); // 第三步:直接对筛选后的结果做业务判断 if (matchedNodes.Any()) { // 复用之前筛选好的节点,不用重复执行DOM查询 var nodes = matchedNodes; if (nodes.Length > 1) { nodes = nodes.Where((source, index) => index != 1).ToArray(); } // [后续原有业务逻辑] } else { LogException("Item is null", taskId, buildId); }
额外注意点
- 无需写
xxx is true这种冗余判断,Any()本身返回布尔值,直接写在if条件里即可 - 优先复用第一次查询到的节点集合,避免重复爬取DOM带来的性能损耗,也能避免两次查询结果不一致的问题
内容的提问来源于stack exchange,提问作者user15274463
相关产品推荐
相关产品推荐

