java异常链本身不记录网页解析失败的源头位置,但通过在自定义异常中封装url、状态码、选择器、html片段等上下文,并以原始异常为cause调用super(message, cause),可精准回溯解析出错的具体环节。

Java异常链本身不记录网页解析失败的源头位置,但配合手动注入的上下文信息(如URL、HTTP状态码、HTML片段、XPath表达式),就能在爬虫解析出错时精准回溯到具体页面元素或请求环节。
在自定义异常中封装爬虫关键上下文
标准异常(如NullPointerException、IllegalArgumentException)不含爬虫特有信息。必须主动构造带上下文的自定义异常,并把原始异常作为cause传入:
- 字段至少包括:url(当前请求地址)、statusCode(HTTP响应码)、selector(CSS/XPath选择器)、htmlSnippet(出错节点附近HTML片段)
- 构造时调用
super(message, cause),确保异常链完整 - 避免只传message而丢弃cause——这是导致源头丢失的最常见错误
在解析逻辑中捕获并增强异常
不要在JSOUP或Jsoup.parse()、Selenium.findElement()等调用后直接吞掉异常。应在catch块中立即包装:
- 对Jsoup解析失败:捕获ParseException或NullPointerException,提取
doc.title()和element.toString().substring(0, Math.min(200, element.toString().length())) - 对XPath提取为空:不是抛空指针,而是检查
nodes.isEmpty()后主动抛出自定义异常,附带所用XPath表达式 - 对JSON解析异常(如Jackson):捕获JsonProcessingException,同时记录原始响应体前512字符
统一日志与外层拦截处理
所有爬虫任务应通过统一入口(如Spring @ControllerAdvice 或自定义Filter)捕获自定义异常:
- 日志输出需包含完整异常链:
log.error("解析失败", e)—— SLF4J/logback会自动打印Caused by层级 - 返回给调度系统的错误信息应结构化,例如:
{"url":"https://xxx","error":"Missing title tag","selector":"h1","cause":"org.jsoup.select.Elements.get: index=0"} - 避免前端或调度层只看到“解析失败”,要能区分是网络超时、页面结构变更,还是反爬拦截(如HTTP 403 + 空body)
避免异常链被意外切断
以下操作会破坏链路,让源头不可见:
- 用
new RuntimeException("解析失败")代替new RuntimeException("解析失败", e) - 在catch中调用
e.printStackTrace()后继续执行,却未重抛或包装 - 自定义异常类未提供接收Throwable的构造函数,或构造函数内未调用
super(message, cause) - 使用Lombok的
@Data或@RequiredArgsConstructor生成构造器,覆盖了异常链必需的父类构造逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











