【发布时间】:2011-07-11 08:36:59
【问题描述】:
我在一个文本中有几个锚标签,
输入:<a href="http://stackoverflow.com" >Take me to StackOverflow</a>
输出:
http://stackoverflow.com
如何在不使用 3rd 方 API 的情况下找到所有这些输入字符串并将其转换为 java 中的输出字符串???
【问题讨论】:
标签: java html-parsing
我在一个文本中有几个锚标签,
输入:<a href="http://stackoverflow.com" >Take me to StackOverflow</a>
输出:
http://stackoverflow.com
如何在不使用 3rd 方 API 的情况下找到所有这些输入字符串并将其转换为 java 中的输出字符串???
【问题讨论】:
标签: java html-parsing
核心 API 中有一些类可用于从锚标记(如果存在!)中获取所有 href 属性:
import java.io.*;
import java.util.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
public class HtmlParseDemo {
public static void main(String [] args) throws Exception {
String html =
"<a href=\"http://stackoverflow.com\" >Take me to StackOverflow</a> " +
"<!-- " +
"<a href=\"http://ignoreme.com\" >...</a> " +
"--> " +
"<a href=\"http://www.google.com\" >Take me to Google</a> " +
"<a>NOOOoooo!</a> ";
Reader reader = new StringReader(html);
HTMLEditorKit.Parser parser = new ParserDelegator();
final List<String> links = new ArrayList<String>();
parser.parse(reader, new HTMLEditorKit.ParserCallback(){
public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
if(t == HTML.Tag.A) {
Object link = a.getAttribute(HTML.Attribute.HREF);
if(link != null) {
links.add(String.valueOf(link));
}
}
}
}, true);
reader.close();
System.out.println(links);
}
}
将打印:
[http://stackoverflow.com, http://www.google.com]【讨论】:
public static void main(String[] args) {
String test = "qazwsx<a href=\"http://stackoverflow.com\">Take me to StackOverflow</a>fdgfdhgfd"
+ "<a href=\"http://stackoverflow2.com\">Take me to StackOverflow2</a>dcgdf";
String regex = "<a href=(\"[^\"]*\")[^<]*</a>";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(test);
System.out.println(m.replaceAll("$1"));
}
注意: Andrzej Doyle 的所有观点都是有效的,如果您的输入中有更多简单的 <a href="X">Y</a>,并且您确定这是可解析的 HTML,那么您使用 HTML 解析器效果更好。
总结一下:
<a>,我发布的正则表达式将不起作用。 (您可以将其视为特殊情况)<a> 标记中有其他属性,它就不起作用。 (同样,您可以将其视为特殊情况)但是,如果您的要求始终将 <a href="X">Y</a> 替换为 "X" 而不考虑上下文,那么我发布的代码将起作用。
【讨论】:
<a class="stripey" href="http://stackoverflow.com">Take me...</a> 会给出假阴性。 <!-- Comment this out for now <a href="http://stackoverflow.com">Take me...</a> --> 将给出误报。在这两种情况下,使用 HTML 解析器都会正确提取 href 属性(包括在第二种情况下根本找不到元素)。
【讨论】:
上面的例子很完美;如果你想解析一个 HTML 文档而不是连接字符串,写这样的东西来补充上面的代码。
上面已有的代码~修改为显示:上面的HtmlParser.java(HtmlParseDemo.java) 用下面的 HtmlPage.java 补充代码。 HtmlPage.properties 文件的内容在本页底部。
HtmlPage.properties 文件中的 main.url 属性为: main.url=http://www.whatever.com/
这样你就可以解析你之后的网址。 :-) 快乐编码:-D
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;
public class HtmlParser
{
public static void main(String[] args) throws Exception
{
String html = HtmlPage.getPage();
Reader reader = new StringReader(html);
HTMLEditorKit.Parser parser = new ParserDelegator();
final List<String> links = new ArrayList<String>();
parser.parse(reader, new HTMLEditorKit.ParserCallback()
{
public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
{
if (t == HTML.Tag.A)
{
Object link = a.getAttribute(HTML.Attribute.HREF);
if (link != null)
{
links.add(String.valueOf(link));
}
}
}
}, true);
reader.close();
// create the header
System.out.println("<html>\n<head>\n <title>Link City</title>\n</head>\n<body>");
// spit out the links and create href
for (String l : links)
{
System.out.print(" <a href=\"" + l + "\">" + l + "</a>\n");
}
// create footer
System.out.println("</body>\n</html>");
}
}
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ResourceBundle;
public class HtmlPage
{
public static String getPage()
{
StringWriter sw = new StringWriter();
ResourceBundle bundle = ResourceBundle.getBundle(HtmlPage.class.getName().toString());
try
{
URL url = new URL(bundle.getString("main.url"));
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
InputStream content = (InputStream) connection.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = in.readLine()) != null)
{
sw.append(line).append("\n");
}
} catch (Exception e)
{
e.printStackTrace();
}
return sw.getBuffer().toString();
}
}
例如,如果在浏览器中查看,这将输出来自http://ebay.com.au/ 的链接。 这是一个子集,因为有很多链接
链接城市 #mainContent http://realestate.ebay.com.au/【讨论】:
如果您需要在不使用 3d 方库的情况下构建它,最可靠的方法(正如已经建议的那样)是使用正则表达式 (java.util.regexp)。
另一种方法是将 html 解析为 XML,或者使用 SAX 解析器来捕获和处理“a”元素的每个实例,或者作为 DOM 文档,然后使用 XPATH 搜索它(参见http://download.oracle.com/javase/6/docs/api/javax/xml/parsers/package-summary.html)。这是有问题的,因为它要求 HTML 页面在标记中完全符合 XML,这是一个非常危险的假设,而不是我推荐的方法,因为大多数“真实”的 html 页面都不符合 XML。
不过,我还是建议您查看现有的为此目的而构建的框架(如 JSoup,上面也提到过)。无需重新发明轮子。
【讨论】: