如何在Java中使用正则表达式解析HTML?

15

请问有没有简单的方法可以使用Java正则表达式在HTML文件中查找href和src标签?
然后,如何获取与标签相关联的URL?

谢谢任何建议。


规范问题:*RegEx匹配开放标签,除了XHTML自包含标签* - Peter Mortensen
7个回答

55

4
这取决于你正在做什么。如果你需要处理来自不同来源的大量HTML,使用HTML解析器可能会失败,并且很可能需要比正则表达式更多的内存和处理能力。例如,Heritrix网络爬虫在HTML页面中使用正则表达式进行链接提取。 - Kris
1
请先回答原始问题,然后建议如何进行优化。许多人访问这个SO问题,希望学习如何使用正则表达式解析HTML,但却发现了他们不想要的东西。使用正则表达式是快速而简单的,您不必下载单独的库才能使其工作。 - Drupad Panchal
2
我不同意这个答案,使用正则表达式处理HTML并不总是错误的 - 正如@Kris所指出的那样:尝试解析完整的HTML文档通常需要有效的HTML,而这并不总是可行的。在你有一个明确定义的情况下,例如查找<a>标签的href属性值,使用正则表达式会提供巨大的帮助。 - Bachi

21
其他答案是正确的。Java Regex API 不是实现你目标的合适工具。使用其他答案中提到的高效、安全、经过充分测试的高级工具。
如果你的问题更关注于正则表达式 API 而不是一个实际问题(比如为了学习),可以使用以下代码实现:
String html = "foo <a href='link1'>bar</a> baz <a href='link2'>qux</a> foo";
Pattern p = Pattern.compile("<a href='(.*?)'>");
Matcher m = p.matcher(html);
while(m.find()) {
   System.out.println(m.group(0));
   System.out.println(m.group(1));
}

输出结果为:

<a href='link1'>
link1
<a href='link2'>
link2
请注意,为了将分组减少到单个标记,必须使用懒惰限定符*?。 Group 0 是整个匹配项,group 1是下一个分组匹配(下一对括号)。

谢谢。虽然这不是一个真正的“适用于所有地方”的正则表达式,但它适用于从谷歌热门趋势返回的数据,我已经花了很长时间来解析它…… - rjha94

7
不要使用正则表达式,而是使用NekoHTML或TagSoup。它们提供了一种SAX或DOM方式来访问HTML文档的桥梁,就像XML一样。

5
如果您想使用HTML解析方法,Dave和我建议使用以下代码来解析字符串数据中的锚点标签并打印它们的href。
由于您只是使用锚点标签,所以只使用正则表达式可能足够了,但如果您想做更多的事情,请选择解析器。 Mozilla HTML解析器是最好的。
File parserLibraryFile = new File("lib/MozillaHtmlParser/native/bin/MozillaParser" + EnviromentController.getSharedLibraryExtension());
                String parserLibrary = parserLibraryFile.getAbsolutePath();
                //  mozilla.dist.bin directory :
                final File mozillaDistBinDirectory = new File("lib/MozillaHtmlParser/mozilla.dist.bin."+ EnviromentController.getOperatingSystemName());

        MozillaParser.init(parserLibrary,mozillaDistBinDirectory.getAbsolutePath());
MozillaParser parser = new MozillaParser();
Document domDocument = parser.parse(data);
NodeList list = domDocument.getElementsByTagName("a");

for (int i = 0; i < list.getLength(); i++) {
    Node n = list.item(i);
    NamedNodeMap m = n.getAttributes();
    if (m != null) {
        Node attrNode = m.getNamedItem("href");
        if (attrNode != null)
           System.out.println(attrNode.getNodeValue());

3

2
我讨厌那个网站。我看到他们仍然不愿意提到给定正则表达式的目标是哪个版本。这个正则表达式(id=2261)使用了命名捕获和条件语句,而Java不支持这两种功能。 - Alan Moore

2

正则表达式只能解析正则语言,这就是为什么它们被称为“正则”表达式。HTML不是一种正则语言,因此无法通过正则表达式进行解析。

另一方面,HTML解析器可以解析HTML,这就是为什么它们被称为HTML解析器的原因。

你应该使用你喜欢的HTML解析器。


1

与广为流传的观点相反,正则表达式是从非结构化文本(如HTML)中提取数据的有用工具。

如果您正在进行复杂的HTML数据提取(例如,在页面中查找所有段落),那么HTML解析可能是最好的选择。但如果您只需要从HREFs获取一些URL,则正则表达式就足够了,并且很难出错。

尝试使用类似下面的表达式:

/<a[^>]+href=["']?([^'"> ]+)["']?[^>]*>/i

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接