问题描述
在 Jenkins Pipeline 中,我们需要对 HTML 文档进行多种操作。之前使用 XMLParser 及 XMLSlurper 库操作 HTML 文档时遇到很多问题,因为 HTML 文档结构松散(比如没有结束标签等等),不是标准的 XML 文件,因此导致 XML 解析失败。
该笔记将整理:在 Groovy 中,操作 HTML 文档的常用方法
解决方案
方案一、使用 Jsoup 类库
项目主页:jsoup Java HTML Parser, with the best of HTML5 DOM methods and CSS selectors.
获取文档的 DOM 对象:Parsing and traversing a Document: jsoup Java HTML parser
使用选择器选择元素:Use selector-syntax to find elements: jsoup Java HTML parser
元素的查找、获取、操作:Use DOM methods to navigate a document: jsoup Java HTML parser
方案二、使用 TagSoup 类库
我们未验证该方法,只是阅读 Grape 手册时发现该方法,这里仅简单记录:
// find the PDF links of the Java specifications @Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='1.2.1') def getHtml() { def parser = new XmlParser(new org.ccil.cowan.tagsoup.Parser()) parser.parse("https://docs.oracle.com/javase/specs/") } html.body.'**'.a.@href.grep(~/.*\.pdf/).each{ println it }
方案一、使用 Jsoup 类库
简单的入门示例
@Grab(group='org.jsoup', module='jsoup', version='1.10.1') import org.jsoup.Jsoup import org.jsoup.nodes.* // Element import org.jsoup.select.* // Elements def htmlString = "<html><head><title>Title of Page</title></></head></html>" def htmlDocument = Jsoup.parse(htmlString) // 找到元素 Elements headings = htmlDocument.select("h1, h2, h3, h4, h5, h6") // 找到 heading 元素 Elements titles = htmlDocument.getElementsByTag("title") // 通过标签获取元素 Elements links = htmlDocument.select("#foo") // 通过 ID 选择元素 // 并获取其内容 titles.first().text() // 然后修改内容 titles.first().text("New Content")
修改元素属性
找到 a 标签,并对属性进行操作:
Element link = doc.select("a").first() link.attr("href") // 获取 href 属性 link.attr("href", "bar") // 修改 href 属性 link.removeAttr("href") // 删除 href 属性 link.attr("data-href", "{}") // 添加 data-href 属性
提取 HTML 代码 / 提取文本内容
// 对于 <div><p></p></div> 文档 String outerHtml = link.outerHtml() // 获取标签的代码,即 <div><p></p></div> String html = link.html() // 获取标签内部的元素,即 <p></p> // 提取文本内容 Document doc = Jsoup.parse(htmlString) Element body = doc.body() def textContent = body.text()
注意事项
如果可能,尽量不要使用任何 XML 类库操作 HTML 文本(因为 HTML 结构松散,允许出现未闭合标签)。
Jsoup 使用 HTML-parser,所以在输出的 HTML 中,总会被添加 <html>…</html> 外围标签,所以要进行处理:
@Grab(group='org.jsoup', module='jsoup', version='1.10.1') import org.jsoup.Jsoup import org.jsoup.nodes.* // Element import org.jsoup.select.* // Elements String html = "<p>some text...</p>"; Document docHtml = Jsoup.parse(html); // 被添加 <html>..</html> 外围标签 println docHtml // <html><head></head><body><p>some text...</p></body></html> // 需要进行提取,以取出自动添加的标签 println docHtml.body().html() // <p>some text...</p> // 该问题还有其他解决方法:使用 XML-parser 解析,但是也有限制(比如,未闭合的标签将导致失败) Document doc = Jsoup.parse(html, "", Parser.xmlParser());
参考文献
Document (jsoup Java HTML Parser 1.14.1-SNAPSHOT API)
Element (jsoup Java HTML Parser 1.14.1-SNAPSHOT API)
html – Get innerHTML via Jsoup – Stack Overflow
Html Slurping in Groovy
java – How to avoid surrounding html head tags in Jsoup parse – Stack Overflow
java – Jsoup: get all heading tags – Stack Overflow
Use DOM methods to navigate a document
Use selector-syntax to find elements: jsoup Java HTML parser