使用Apache Tika结合XPath提取网页链接href属性值失败如何解决
问题分析
你遇到的问题核心有两个:XPath语法使用错误、ContentHandler选型不匹配属性提取需求。
1. XPath写法错误点
- 不要给属性节点追加
text():属性节点本身的字符串值就是属性内容,不存在子文本节点,加text()会导致匹配结果为空。 - 不要给href属性加xhtml命名空间前缀:XHTML规范中,默认命名空间仅作用于元素节点,不带前缀的属性不属于任何命名空间,
@xhtml:href无法匹配到实际的href属性。
你之前测试的几个XPath的错误原因:
//xhtml:a/@xhtml:href:href属性无xhtml前缀,匹配失效//xhtml:a/@href/text():多余的text()导致匹配失效//xhtml:a/@href:XPath本身语法正确,失效原因是ContentHandler使用错误//@xhtml:href/text():同时存在前缀错误和多余text()的问题
2. ContentHandler选型错误
你使用的MatchingContentHandler+ToHTMLContentHandler的组合,设计用途是提取匹配元素的内部标签/文本内容,无法直接返回元素的属性值,哪怕XPath写对也拿不到href的内容。
解决方案
方案1:直接使用Tika内置的LinkContentHandler(推荐,无需写XPath)
如果你的需求只是提取页面所有链接的href属性,Tika自带了专门的LinkContentHandler,直接用就行,代码示例:
HtmlParser parser = new HtmlParser(); ParseContext pcontext = new ParseContext(); LinkContentHandler linkHandler = new LinkContentHandler(); try { parser.parse(urlContentStream, linkHandler, new Metadata(), pcontext); // 所有链接对象都存在list里,直接取getUri()就是href值 List<Link> links = linkHandler.getLinks(); for (Link link : links) { System.out.println(link.getUri()); } } catch (Exception e) { // 异常处理逻辑 }
方案2:自定义ContentHandler实现XPath属性提取
如果你确实需要用XPath自定义匹配规则来取属性,可以自己实现一个简单的ContentHandler收集属性值,代码示例:
XPathParser xhtmlParser = new XPathParser("xhtml", XHTMLContentHandler.XHTML); // 正确的XPath写法,匹配所有xhtml命名空间下a标签的href属性 Matcher hrefMatcher = xhtmlParser.parse("//xhtml:a/@href"); // 自定义ContentHandler收集匹配到的属性值 List<String> hrefList = new ArrayList<>(); ContentHandler handler = new DefaultHandler() { @Override public void characters(char[] ch, int start, int length) throws SAXException { // 匹配到属性节点时,characters方法收到的就是属性值 if (hrefMatcher.isMatch()) { hrefList.add(new String(ch, start, length)); } } }; HtmlParser parser = new HtmlParser(); ParseContext pcontext = new ParseContext(); try { parser.parse(urlContentStream, handler, new Metadata(), pcontext); // 输出所有收集到的href值 hrefList.forEach(System.out::println); } catch (Exception e) { // 异常处理逻辑 }
内容的提问来源于stack exchange,提问作者Pierre
相关产品推荐
相关产品推荐

