¿Cómo se descarga mediante programación una página web en Java?

117

Me gustaría poder obtener el html de una página web y guardarlo en a String, para poder procesarlo. Además, ¿cómo podría manejar varios tipos de compresión?

¿Cómo haría eso usando Java?

jjnguy
fuente
Este es básicamente un caso especial de stackoverflow.com/questions/921262/…
Robin Green

Respuestas:

110

Aquí hay un código probado usando la clase URL de Java . Sin embargo, recomendaría hacer un mejor trabajo que el que hago aquí para manejar las excepciones o pasarlas por la pila de llamadas.

public static void main(String[] args) {
    URL url;
    InputStream is = null;
    BufferedReader br;
    String line;

    try {
        url = new URL("http://stackoverflow.com/");
        is = url.openStream();  // throws an IOException
        br = new BufferedReader(new InputStreamReader(is));

        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    } catch (MalformedURLException mue) {
         mue.printStackTrace();
    } catch (IOException ioe) {
         ioe.printStackTrace();
    } finally {
        try {
            if (is != null) is.close();
        } catch (IOException ioe) {
            // nothing to see here
        }
    }
}
Bill el lagarto
fuente
16
DataInputStream.readLine () está en desuso, pero aparte de ese muy buen ejemplo. Usé un InputStreamReader () envuelto en un BufferedReader () para obtener la función readLine ().
mjh2007
2
Esto no tiene en cuenta la codificación de caracteres, por lo que, si bien parecerá que funciona para texto ASCII, eventualmente resultará en 'caracteres extraños' cuando haya una falta de coincidencia.
artbristol
En la tercera línea, reemplace DataInputStreama BufferedReader. Y reemplazar "dis = new DataInputStream(new BufferedInputStream(is));"a"dis = new BufferedReader(new InputStreamReader(is));"
kolobok
1
@akapelko Gracias. Actualicé mi respuesta para eliminar las llamadas a métodos obsoletos.
Bill the Lizard
2
¿Qué hay de cerrar el InputStreamReader?
Alexander - Reincorpora a Monica
170

Usaría un analizador HTML decente como Jsoup . Entonces es tan fácil como:

String html = Jsoup.connect("http://stackoverflow.com").get().html();

Maneja GZIP y respuestas fragmentadas y codificación de caracteres de forma totalmente transparente. También ofrece más ventajas, como el desplazamiento de HTML y la manipulación mediante selectores de CSS, como puede hacer jQuery. Solo tienes que agarrarlo como Document, no como un String.

Document document = Jsoup.connect("http://google.com").get();

Realmente no desea ejecutar métodos básicos de cadena o incluso expresiones regulares en HTML para procesarlo.

Ver también:

BalusC
fuente
3
Buena respuesta. Un poco tarde. ;)
jjnguy
59
Mejor que nunca.
BalusC
Biblioteca fantástica :) Gracias por eso.
Jakub P.
¿Por qué nadie me habló de .html () antes? Busqué mucho en cómo almacenar fácilmente el html obtenido por Jsoup y eso ayuda mucho.
Avamander
para los recién llegados, si usa esta biblioteca en Android, debe usarla en un hilo diferente porque se ejecuta de forma predeterminada en el mismo hilo de la aplicación, lo que hará que la aplicación lanceNetworkOnMainThreadException
Mohammed Elrashied
25

La respuesta de Bill es muy buena, pero es posible que desee hacer algunas cosas con la solicitud como compresión o agentes de usuario. El siguiente código muestra cómo puede varios tipos de compresión para sus solicitudes.

URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // Cast shouldn't fail
HttpURLConnection.setFollowRedirects(true);
// allow both GZip and Deflate (ZLib) encodings
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
String encoding = conn.getContentEncoding();
InputStream inStr = null;

// create the appropriate stream wrapper based on
// the encoding type
if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
    inStr = new GZIPInputStream(conn.getInputStream());
} else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
    inStr = new InflaterInputStream(conn.getInputStream(),
      new Inflater(true));
} else {
    inStr = conn.getInputStream();
}

Para configurar también el agente de usuario, agregue el siguiente código:

conn.setRequestProperty ( "User-agent", "my agent name");
jjnguy
fuente
Para aquellos que buscan convertir InputStream a una cadena, vea esta respuesta .
SSight3
setFollowRedirects ayuda, yo uso setInstanceFollowRedirects en mi caso, obtenía páginas web vacías en muchos casos antes de usar eso. Supongo que intenta usar la compresión para descargar el archivo más rápido.
gouessej
12

Bueno, podría optar por las bibliotecas integradas, como URL y URLConnection , pero no dan mucho control.

Personalmente, iría con la biblioteca Apache HTTPClient .
Editar: Apache ha establecido el final de la vida útil de HTTPClient. El reemplazo es: Componentes HTTP

Jon Skeet
fuente
¿No hay una versión java de System.Net.WebRequest?
FlySwat
1
Más o menos eso sería URL. :-) Por ejemplo: nueva URL (" google.com"). OpenStream () // => InputStream
Daniel Spiewak
1
@Jonathan: Lo que dijo Daniel, en su mayor parte, aunque WebRequest te da más control que URL. HTTPClient tiene una funcionalidad más cercana, en mi opinión.
Jon Skeet
9

Todos los enfoques mencionados anteriormente no descargan el texto de la página web tal como aparece en el navegador. En estos días, una gran cantidad de datos se cargan en los navegadores a través de scripts en páginas html. ninguna de las técnicas mencionadas admite scripts, solo descarga el texto html solamente. HTMLUNIT admite los javascripts. por lo tanto, si desea descargar el texto de la página web como se ve en el navegador, debe usar HTMLUNIT .

usuario3690910
fuente
1

Lo más probable es que necesite extraer el código de una página web segura (protocolo https). En el siguiente ejemplo, el archivo html se guarda en c: \ temp \ filename.html ¡Disfrute!

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

/**
 * <b>Get the Html source from the secure url </b>
 */
public class HttpsClientUtil {
    public static void main(String[] args) throws Exception {
        String httpsURL = "https://stackoverflow.com";
        String FILENAME = "c:\\temp\\filename.html";
        BufferedWriter bw = new BufferedWriter(new FileWriter(FILENAME));
        URL myurl = new URL(httpsURL);
        HttpsURLConnection con = (HttpsURLConnection) myurl.openConnection();
        con.setRequestProperty ( "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0" );
        InputStream ins = con.getInputStream();
        InputStreamReader isr = new InputStreamReader(ins, "Windows-1252");
        BufferedReader in = new BufferedReader(isr);
        String inputLine;

        // Write each line into the file
        while ((inputLine = in.readLine()) != null) {
            System.out.println(inputLine);
            bw.write(inputLine);
        }
        in.close(); 
        bw.close();
    }
}
Especialista de control de calidad
fuente
0

En una caja Unix / Linux, podría simplemente ejecutar 'wget' pero esta no es realmente una opción si está escribiendo un cliente multiplataforma. Por supuesto, esto supone que realmente no desea hacer mucho con los datos que descarga entre el momento en que los descarga y el momento en que llegan al disco.

Timo Geusch
fuente
También comenzaría con este enfoque y lo refactorizaría más tarde si no fuera suficiente
Dustin Getz
0

Jetty tiene un cliente HTTP que se puede utilizar para descargar una página web.

package com.zetcode;

import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;

public class ReadWebPageEx5 {

    public static void main(String[] args) throws Exception {

        HttpClient client = null;

        try {

            client = new HttpClient();
            client.start();

            String url = "http://www.something.com";

            ContentResponse res = client.GET(url);

            System.out.println(res.getContentAsString());

        } finally {

            if (client != null) {

                client.stop();
            }
        }
    }
}

El ejemplo imprime el contenido de una página web simple.

En un tutorial de Lectura de una página web en Java , he escrito seis ejemplos de cómo descargar una página web programáticamente en Java usando URL, JSoup, HtmlCleaner, Apache HttpClient, Jetty HttpClient y HtmlUnit.

Jan Bodnar
fuente
0

Obtenga ayuda de esta clase para obtener código y filtrar información.

public class MainActivity extends AppCompatActivity {

    EditText url;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        setContentView( R.layout.activity_main );

        url = ((EditText)findViewById( R.id.editText));
        DownloadCode obj = new DownloadCode();

        try {
            String des=" ";

            String tag1= "<div class=\"description\">";
            String l = obj.execute( "http://www.nu.edu.pk/Campus/Chiniot-Faisalabad/Faculty" ).get();

            url.setText( l );
            url.setText( " " );

            String[] t1 = l.split(tag1);
            String[] t2 = t1[0].split( "</div>" );
            url.setText( t2[0] );

        }
        catch (Exception e)
        {
            Toast.makeText( this,e.toString(),Toast.LENGTH_SHORT ).show();
        }

    }
                                        // input, extrafunctionrunparallel, output
    class DownloadCode extends AsyncTask<String,Void,String>
    {
        @Override
        protected String doInBackground(String... WebAddress) // string of webAddress separate by ','
        {
            String htmlcontent = " ";
            try {
                URL url = new URL( WebAddress[0] );
                HttpURLConnection c = (HttpURLConnection) url.openConnection();
                c.connect();
                InputStream input = c.getInputStream();
                int data;
                InputStreamReader reader = new InputStreamReader( input );

                data = reader.read();

                while (data != -1)
                {
                    char content = (char) data;
                    htmlcontent+=content;
                    data = reader.read();
                }
            }
            catch (Exception e)
            {
                Log.i("Status : ",e.toString());
            }
            return htmlcontent;
        }
    }
}
Sohaib Aslam
fuente
0

Para hacerlo utilizando el poderoso Files.copy de NIO.2 (InputStream in, Path target):

URL url = new URL( "http://download.me/" );
Files.copy( url.openStream(), Paths.get("downloaded.html" ) );
Jan Tibar
fuente
-1

Usé la respuesta real a esta publicación ( url ) y escribí la salida en un archivo.

package test;

import java.net.*;
import java.io.*;

public class PDFTest {
    public static void main(String[] args) throws Exception {
    try {
        URL oracle = new URL("http://www.fetagracollege.org");
        BufferedReader in = new BufferedReader(new InputStreamReader(oracle.openStream()));

        String fileName = "D:\\a_01\\output.txt";

        PrintWriter writer = new PrintWriter(fileName, "UTF-8");
        OutputStream outputStream = new FileOutputStream(fileName);
        String inputLine;

        while ((inputLine = in.readLine()) != null) {
            System.out.println(inputLine);
            writer.println(inputLine);
        }
        in.close();
        } catch(Exception e) {

        }

    }
}
A_01
fuente