如何使用XmlSlurper解析非格式良好的HTML

时间:2015-01-23 12:41:28

标签: html groovy xmlslurper

我尝试使用XmlSlurper解析格式不正确的HTML页面,the Eclipse download site W3C validator在页面中显示多个错误。

我尝试了this帖子

中的容错解析器
@Grab(group='net.sourceforge.nekohtml', module='nekohtml', version='1.9.14')
import org.cyberneko.html.parsers.SAXParser 
import groovy.util.XmlSlurper

// Getting the xhtml page thanks to Neko SAX parser 
def mirrors = new XmlSlurper(new SAXParser()).parse("http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR1a/eclipse-jee-luna-SR1a-linux-gtk-x86_64.tar.gz")    

mirrors.'**'

不幸的是,看起来并非所有内容都被解析为XML对象。有缺陷的子树被忽略了。

E.g。 page.depthFirst().find { it.text() == 'North America'}返回null而不是页面中的H4元素。

是否有一些可靠的方法来解析groovy中的任何HTML内容?

2 个答案:

答案 0 :(得分:7)

通过以下代码,它可以很好地解析(没有错误):

@Grab(group='net.sourceforge.nekohtml', module='nekohtml', version='1.9.14') 
import org.cyberneko.html.parsers.SAXParser 
import groovy.util.XmlSlurper

def parser = new SAXParser()
def page = new XmlSlurper(parser).parse('http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR1a/eclipse-jee-luna-SR1a-linux-gtk-x86_64.tar.gz')

但是,我不知道您想要找到哪些元素。

此处找到All mirrors

page.depthFirst().find { 
    it.text() == 'All mirrors'
}.@href

修改

两个输出均为null

println page.depthFirst().find { it.text() == 'North America'}

println page.depthFirst().find { it.text().contains('North America')}

编辑2

下面您可以找到一个下载文件并正确解析它的工作示例。我使用wget下载文件(使用groovy下载它时出了问题 - 不知道是什么)

@Grab(group='net.sourceforge.nekohtml', module='nekohtml', version='1.9.14') 
import org.cyberneko.html.parsers.SAXParser 
import groovy.util.XmlSlurper

def host = 'http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR1a/eclipse-jee-luna-SR1a-linux-gtk-x86_64.tar.gz'
def temp = File.createTempFile('eclipse', 'tmp')
temp.deleteOnExit()

def cmd = ['wget', host, '-O', temp.absolutePath].execute()
cmd.waitFor()
cmd.exitValue()

def parser = new SAXParser()
def page = new XmlSlurper(parser).parseText(temp.text)

println page.depthFirst().find { it.text() == 'North America'}
println page.depthFirst().find { it.text().contains('North America')}

编辑3

最后问题解决了。如果未指定url.toURL().text标头,则使用groovy的User-Agent会导致问题。现在它可以正常工作并找到元素 - 没有使用外部工具。

@Grab(group='net.sourceforge.nekohtml', module='nekohtml', version='1.9.14') 
import org.cyberneko.html.parsers.SAXParser 
import groovy.util.XmlSlurper

def host = 'http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR1a/eclipse-jee-luna-SR1a-linux-gtk-x86_64.tar.gz'

def parser = new SAXParser()
def page = new XmlSlurper(parser).parseText(host.toURL().getText(requestProperties: ['User-Agent': 'Non empty']))

assert page.depthFirst().find { it.text() == 'North America'}
assert page.depthFirst().find { it.text().contains('North America')}

答案 1 :(得分:3)

我喜欢tagsoup SAX解析器,它说它旨在解析“糟糕,讨厌和野蛮”的HTML。

它可以很容易地与XmlSlurper结合使用:

@Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='1.2')
def parser = new XmlSlurper(new org.ccil.cowan.tagsoup.Parser())

def page = parser.parse('http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR1a/eclipse-jee-luna-SR1a-linux-gtk-x86_64.tar.gz')

println page.depthFirst().find { it.text() == 'North America'}
println page.depthFirst().find { it.text().contains('North America')}    

这会导致非空输出。