我正在编写一个爬虫/解析器,它应该能够处理不同类型的内容,包括 RSS、Atom 和纯 html 文件。为了确定正确的解析器,我编写了一个名为 ParseFactory 的类,它接受一个 URL,尝试检测内容类型,并返回正确的解析器。
不幸的是,使用 URLConnection 中提供的方法检查内容类型并不总是有效。例如,
String contentType = url.openConnection().getContentType();
并不总是提供正确的内容类型(例如,“text/html”应该是 RSS),或者不允许区分 RSS 和 Atom(例如,“application/xml”既可以是 Atom,也可以是 RSS feed)。为了解决这个问题,我开始在InputStream中寻找线索。问题是我在设计一个优雅的类设计时遇到了困难,我只需要下载一次InputStream。在我当前的设计中,我首先编写了一个单独的类来确定正确的内容类型,接下来 ParseFactory 使用此信息创建相应解析器的实例,而当调用“parse()”方法时,该实例会再次下载整个 InputStream。
public Parser createParser(){
InputStream inputStream = null;
String contentType = null;
String contentEncoding = null;
ContentTypeParser contentTypeParser = new ContentTypeParser(this.url);
Parser parser = null;
try {
inputStream = new BufferedInputStream(this.url.openStream());
contentTypeParser.parse(inputStream);
contentType = contentTypeParser.getContentType();
contentEncoding = contentTypeParser.getContentEncoding();
assert (contentType != null);
inputStream = new BufferedInputStream(this.url.openStream());
if (contentType.equals(ContentTypes.rss))
{
logger.info("RSS feed detected");
parser = new RssParser(this.url);
parser.parse(inputStream);
}
else if (contentType.equals(ContentTypes.atom))
{
logger.info("Atom feed detected");
parser = new AtomParser(this.url);
}
else if (contentType.equals(ContentTypes.html))
{
logger.info("html detected");
parser = new HtmlParser(this.url);
parser.setContentEncoding(contentEncoding);
}
else if (contentType.equals(ContentTypes.UNKNOWN))
logger.debug("Unable to recognize content type");
if (parser != null)
parser.parse(inputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return parser;
}
基本上,我正在寻找一种解决方案,使我能够消除第二个“inputStream = new BufferedInputStream(this.url.openStream())”。
任何帮助将不胜感激!
旁注 1:为了完整起见,我还尝试使用 URLConnection.guessContentTypeFromStream(inputStream) 方法,但这太频繁地返回 null。
旁注 2:XML 解析器(Atom 和 Rss)基于 SAXParser,即 Jsoup 上的 Html 解析器。
最佳答案
你可以只调用mark
和reset
吗?
inputStream = new BufferedInputStream(this.url.openStream());
inputStream.mark(2048); // Or some other sensible number
contentTypeParser.parse(inputStream);
contentType = contentTypeParser.getContentType();
contentEncoding = contentTypeParser.getContentEncoding();
inputstream.reset(); // Let the parser have a crack at it now
关于java - 输入流根据内容由不同的对象处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6774701/