6

我正在尝试通过 URLConnection 获取整个网页。

最有效的方法是什么?

我已经这样做了:

URL url = new URL("http://www.google.com/");
URLConnection connection;
connection = url.openConnection();
InputStream in = connection.getInputStream();        
BufferedReader bf = new BufferedReader(new InputStreamReader(in));
StringBuffer html = new StringBuffer();
String line = bf.readLine();
while(line!=null){
    html.append(line);
    line = bf.readLine();
}
bf.close();

html 拥有整个 HTML 页面。

4

5 回答 5

8

我认为这最好的方法。页面的大小是固定的(“就是这样”),因此您无法提高内存。也许您可以在拥有内容后对其进行压缩,但在这种形式下它们并不是很有用。我想最终你会想要将 HTML 解析为 DOM 树。

您为并行读取所做的任何事情都会使解决方案过于复杂。

我建议使用默认大小为 2048 或 4096 的 StringBuilder。

为什么您认为您发布的代码还不够?您听起来好像对过早优化感到内疚。

带着你所有的东西跑,晚上睡觉。

于 2010-10-12T20:32:06.127 回答
3

你想对获得的 HTML 做什么?解析它?很高兴知道一个体面的 HTML 解析器已经可以有一个构造函数或方法参数,它直接采用URLor InputStream,这样您就不必担心这样的流性能。

假设您想要做的所有事情都在您之前的问题中进行了描述,例如使用 Jsoup,您可以获得所有这些非常容易的新闻链接,如下所示:

Document document = Jsoup.connect("http://news.google.com.ar/nwshp?hl=es&tab=wn").get();
Elements newsLinks = document.select("h2.title a:eq(0)");
for (Element newsLink : newsLinks) {
    System.out.println(newsLink.attr("href"));
}

这仅在几秒钟后产生以下结果:

http://www.infobae.com/mundo/541259-100970-0-Pinera-confirmo-que-el-rescate-comenzara-las-20-y-durara-24-y-48-horas
http://www.lagaceta.com.ar/nota/403112/Argentina/Boudou-disculpo-con-DAIA-pero-volvio-cuestionar-medios.html
http://www.abc.es/agencias/noticia.asp?noticia=550415
http://www.google.com/hostednews/epa/article/ALeqM5i6x9rhP150KfqGJvwh56O-thi4VA?docId=1383133
http://www.abc.es/agencias/noticia.asp?noticia=550292
http://www.univision.com/contentroot/wirefeeds/noticias/8307387.shtml
http://noticias.terra.com.ar/internacionales/ecuador-apoya-reclamo-argentino-por-ejercicios-en-malvinas,3361af2a712ab210VgnVCM4000009bf154d0RCRD.html
http://www.infocielo.com/IC/Home/index.php?ver_nota=22642
http://www.larazon.com.ar/economia/Cristina-Fernandez-Censo-indispensable-pais_0_176100098.html
http://www.infobae.com/finanzas/541254-101275-0-Energeticas-llevaron-la-Bolsa-portena-ganancias
http://www.telam.com.ar/vernota.php?tipo=N&idPub=200661&id=381154&dis=1&sec=1
http://www.ambito.com/noticia.asp?id=547722
http://www.canal-ar.com.ar/noticias/noticiamuestra.asp?Id=9469
http://www.pagina12.com.ar/diario/cdigital/31-154760-2010-10-12.html
http://www.lanacion.com.ar/nota.asp?nota_id=1314014
http://www.rpp.com.pe/2010-10-12-ganador-del-pulitzer-destaca-nobel-de-mvll-noticia_302221.html
http://www.lanueva.com/hoy/nota/b44a7553a7/1/79481.html
http://www.larazon.com.ar/show/sdf_0_176100096.html
http://www.losandes.com.ar/notas/2010/10/12/batista-siento-comodo-dieron-respaldo-520595.asp
http://deportes.terra.com.ar/futbol/los-rumores-empiezan-a-complicar-la-vida-de-river-y-vuelve-a-sonar-gallego,a24483b8702ab210VgnVCM20000099f154d0RCRD.html
http://www.clarin.com/deportes/futbol/Exigieron-Roman-regreso-Huracan_0_352164993.html
http://www.el-litoral.com.ar/leer_noticia.asp?idnoticia=146622
http://www.nuevodiarioweb.com.ar/nota/181453/Locales/C%C3%A1ncer_mama:_200_casos_a%C3%B1o_Santiago.html
http://www.ultimahora.com/notas/367322-Funcionarios-sanitarios-capacitaran-sobre-cancer-de-mama
http://www.lanueva.com/hoy/nota/65092f2044/1/79477.html
http://www.infobae.com/policiales/541220-101275-0-Se-suspendio-la-declaracion-del-marido-Fernanda-Lemos
http://www.clarin.com/sociedad/educacion/titulo_0_352164863.html

是否有人已经说过正则表达式绝对是解析 HTML 的错误工具?;)

也可以看看:

于 2010-10-12T21:14:25.580 回答
2

您可以尝试使用来自 apache 的 commons-io (http://commons.apache.org/io/api-release/org/apache/commons/io/IOUtils.html)

new String(IOUtils.toCharArray(connection.getInputStream()))
于 2010-10-12T20:38:16.027 回答
2

您的方法看起来不错,但是您可以通过避免为每行创建中间 String 对象来提高效率。

这样做的方法是直接读入一个临时的 char[] 缓冲区。

这是执行此操作的代码的略微修改版本(为了清楚起见,减去所有错误检查、异常处理等):

        URL url = new URL("http://www.google.com/");
        URLConnection connection;
        connection = url.openConnection();
        InputStream in = connection.getInputStream();        
        BufferedReader bf = new BufferedReader(new InputStreamReader(in));
        StringBuffer html = new StringBuffer();

        char[] charBuffer = new char[4096];
        int count=0;

        do {
            count=bf.read(charBuffer, 0, 4096);
            if (count>=0) html.append(charBuffer,0,count);
        } while (count>0);
        bf.close();

为了获得更高的性能,如果要频繁调用此代码,您当然可以做一些额外的事情,例如预先分配字符数组和 StringBuffer。

于 2010-10-12T20:45:23.477 回答
1

有一些技术上的考虑。您可能希望使用 HTTPURLConnection 而不是 URLConnection。

HTTPURLConnection 支持分块传输编码,它允许您以块的形式处理数据,而不是在开始工作之前缓冲所有内容。这可以改善用户体验。

Also, HTTPURLConnection supports persistent connections. Why close that connection if you're going to request another resource right away? Keeping the TCP connection open with the web server allows your application to quickly download multiple resources without spending the overhead (latency) of establishing a new TCP connection for each resource.

Tell the server that you support gzip and wrap a BufferedReader around GZIPInputStream if the response header says the content is compressed.

于 2010-10-12T21:34:08.607 回答