如何解决Java抓取Morningstar数据时实体引用需以';'结尾的错误
错误原因
- 你使用的Java原生
DocumentBuilder是严格XML格式校验的解析器,目标站点返回的是普通HTML页面,存在大量未转义的&字符(通常出现在页面内的链接参数、资源地址中),XML解析器会将&后的字符识别为实体引用,要求必须以;结尾,匹配失败就会抛出该SAX解析异常。
解决方法
方案1(推荐):替换为HTML专用解析器Jsoup
Jsoup对非规范HTML的兼容性极高,原生支持CSS选择器查询,代码实现更简单,还自带HTTP请求能力,不需要手动处理HTTP连接:
- 先引入Jsoup依赖(Maven示例):
<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.17.2</version> </dependency>
- 替换原有解析逻辑:
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; public class MSExtrctor { public static void main(String[] args) throws Exception { String url = "https://www.morningstar.co.uk/uk/funds/snapshot/snapshot.aspx?id=F00000WYA1"; // 模拟浏览器UA避免被站点拦截 Document doc = Jsoup.connect(url) .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") .get(); Elements starEl = doc.select("span[class*=rating_sprite star]"); String classVal = starEl.attr("class"); // 提取星级,class值格式为rating_sprite starX,X就是星级数字 String starLevel = classVal.replace("rating_sprite star", ""); System.out.println("基金星级:" + starLevel); } }
方案2:保留原有XML/XPath逻辑
如果必须使用现有XPath逻辑,需要先用JTidy工具将原始HTML清理为符合XML规范的XHTML格式,再交给DOM解析器处理:
- 引入JTidy依赖
<dependency> <groupId>net.sf.jtidy</groupId> <artifactId>jtidy</artifactId> <version>r938</version> </dependency>
- 在原有代码调用
builder.parse前,先用JTidy处理输入流:
// 获取到connection.getInputStream()后替换原有builder.parse逻辑 Tidy tidy = new Tidy(); tidy.setXHTML(true); tidy.setQuiet(true); tidy.setShowWarnings(false); org.w3c.dom.Document document = tidy.parseDOM(connection.getInputStream(), null);
内容的提问来源于stack exchange,提问作者serah
相关产品推荐
相关产品推荐

