Leggi l'URL alla stringa in poche righe di codice java


151

Sto cercando di trovare l'equivalente di Java con Groovy:

String content = "http://www.google.com".toURL().getText();

Voglio leggere il contenuto di un URL in stringa. Non voglio inquinare il mio codice con flussi e loop bufferizzati per un compito così semplice. Ho esaminato HttpClient di apache ma non vedo l'implementazione a una o due righe.


6
Perché non creare semplicemente una classe di utilità che incapsuli tutti i flussi e i loop buffer "inquinati"? È inoltre possibile utilizzare quella classe per gestire cose come la chiusura del socket prima del completamento del flusso e per gestire i blocchi I / O su una connessione lenta. Dopotutto, questo è OO: incapsula la funzionalità e nascondila alla tua classe principale.
Jonathan B,

1
Non può essere fatto su una o due righe.
Thorbjørn Ravn Andersen,

Risposte:


130

Ora che è passato del tempo dall'accettazione della risposta originale, esiste un approccio migliore:

String out = new Scanner(new URL("http://www.google.com").openStream(), "UTF-8").useDelimiter("\\A").next();

Se si desidera un'implementazione leggermente più completa, che non è una riga singola, procedere come segue:

public static String readStringFromURL(String requestURL) throws IOException
{
    try (Scanner scanner = new Scanner(new URL(requestURL).openStream(),
            StandardCharsets.UTF_8.toString()))
    {
        scanner.useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
}

14
Non dimenticare che devi chiamare Scanner#close()più tardi.
Marcelo,

2
L'espressione regolare \\ A corrisponde all'inizio dell'input. Ciò dice a Scanner di tokenizzare l'intero flusso, dall'inizio al (illogico) inizio successivo.
Runa,

7
Pulito, ma fallisce se la pagina web non restituisce alcun contenuto (""). Devi String result = scanner.hasNext() ? scanner.next() : "";gestirlo.
NateS,

3
@ccleve sarebbe utile aggiungere importazioni qui, ci sono più scanner e URL in Java
kiedysktos

2
@ccleve puoi aggiornare il link "Questo spiega \\ A:"?
Imaskar

95

Questa risposta si riferisce a una versione precedente di Java. Potresti voler guardare la risposta di ccleve.


Ecco il modo tradizionale per farlo:

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

public class URLConnectionReader {
    public static String getText(String url) throws Exception {
        URL website = new URL(url);
        URLConnection connection = website.openConnection();
        BufferedReader in = new BufferedReader(
                                new InputStreamReader(
                                    connection.getInputStream()));

        StringBuilder response = new StringBuilder();
        String inputLine;

        while ((inputLine = in.readLine()) != null) 
            response.append(inputLine);

        in.close();

        return response.toString();
    }

    public static void main(String[] args) throws Exception {
        String content = URLConnectionReader.getText(args[0]);
        System.out.println(content);
    }
}

Come ha suggerito @extraneon , ioutils ti consente di farlo in un modo molto eloquente che è ancora nello spirito di Java:

 InputStream in = new URL( "http://jakarta.apache.org" ).openStream();

 try {
   System.out.println( IOUtils.toString( in ) );
 } finally {
   IOUtils.closeQuietly(in);
 }

5
Potresti rinominare il metodo principale per, diciamo getText, passare la stringa URL come parametro e avere un solo liner:String content = URLConnectionReader.getText("http://www.yahoo.com/");
Goran Jovic

7
La stringa non conterrà alcun carattere di interruzione di riga (a causa dell'uso di BufferReader.readLine () che le rimuove), quindi non sarà esattamente il contenuto dell'URL.
Benoît Guédas,

@Benoit Guedas, quindi come mantenere le interruzioni di linea?
user1788736

76

Oppure usa semplicemente Apache Commons IOUtils.toString(URL url)o la variante che accetta anche un parametro di codifica.


12
+1 Grazie, ha funzionato perfettamente. Una riga di codice E chiude il flusso! Si noti che IOUtils.toString(URL)è obsoleto. IOUtils.toString(URL url, String encoding)è preferito.
gMale

1
IOUtils.toString(url, (Charset) null)per raggiungere un risultato simile.
franckysnow,

3
Una riga di codice e decine di megabyte di file di classe estranei che sono ora in fase di esecuzione. Includere una gigantesca libreria per evitare di scrivere alcune (in realtà una) riga di codice non è una grande decisione.
Jeffrey Blattman,

1
@JeffreyBlattman se lo stai usando solo una volta nella tua applicazione, probabilmente non è una decisione così intelligente, ma se lo stai usando più frequentemente e altre cose dal pacchetto commons-io, potrebbe essere di nuovo una decisione intelligente. Dipende anche dall'applicazione che stai scrivendo. Se si tratta di un'app mobile o desktop, potresti pensare due volte a gonfiare il footprint di memoria con librerie aggiuntive. Se si tratta di un'applicazione server in esecuzione su una macchina RAM da 64 GB, ignora solo questi 10 MB - la memoria è economica al giorno d'oggi e se l'impronta di base è dell'1,5% o il 2% della tua memoria totale non importa
big data nerd

24

Ora che è trascorso più tempo, ecco un modo per farlo in Java 8:

URLConnection conn = url.openConnection();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
    pageText = reader.lines().collect(Collectors.joining("\n"));
}

Quando utilizzo questo esempio sul servizio http://www.worldcat.org/webservices/catalog/search/opensearchweb, ottengo solo le prime due righe di xml.
Ortomala Lokni,

L'errore 400 è perché è necessaria una chiave per utilizzare questo servizio web. Il problema è che questo servizio web invia un po 'di xml, quindi impiega alcuni secondi per eseguire l'elaborazione e quindi inviare la seconda parte dell'xml. InputStream viene chiuso durante l'intervallo e non tutto il contenuto viene consumato. Ho risolto il problema utilizzando la libreria apache del componente http hc.apache.org/httpcomponents-client-ga
Ortomala Lokni

17

C'è un modo ancora migliore di Java 9:

URL u = new URL("http://www.example.com/");
try (InputStream in = u.openStream()) {
    return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}

Come nell'esempio originale, questo presuppone che il contenuto sia codificato UTF-8. (Se hai bisogno di qualcosa di più intelligente di quello, devi creare un URLConnection e usarlo per capire la codifica.)


1
Grazie, era esattamente quello che stavo cercando. Può anche essere usato con getClass().getResourceAsStream(...)per aprire file di testo all'interno del vaso.
rjh

8

Esempio aggiuntivo usando Guava:

URL xmlData = ...
String data = Resources.toString(xmlData, Charsets.UTF_8);

1
I documenti di Guava dicono link : Nota che sebbene questi metodi utilizzino i parametri {@link URL}, di solito non sono appropriati per le risorse HTTP o altre risorse non classpath
gaal


3

Quanto segue funziona con Java 7/8, URL sicuri e mostra come aggiungere un cookie anche alla tua richiesta. Nota che questa è principalmente una copia diretta di quest'altra ottima risposta in questa pagina , ma ha aggiunto l'esempio di cookie e chiarimenti in quanto funziona anche con URL sicuri ;-)

Se è necessario connettersi a un server con un certificato non valido o un certificato autofirmato, ciò genererà errori di sicurezza a meno che non si importi il ​​certificato. Se è necessaria questa funzionalità, è possibile prendere in considerazione l'approccio dettagliato in questa risposta a questa domanda correlata su StackOverflow.

Esempio

String result = getUrlAsString("https://www.google.com");
System.out.println(result);

uscite

<!doctype html><html itemscope="" .... etc

Codice

import java.net.URL;
import java.net.URLConnection;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public static String getUrlAsString(String url)
{
    try
    {
        URL urlObj = new URL(url);
        URLConnection con = urlObj.openConnection();

        con.setDoOutput(true); // we want the response 
        con.setRequestProperty("Cookie", "myCookie=test123");
        con.connect();

        BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));

        StringBuilder response = new StringBuilder();
        String inputLine;

        String newLine = System.getProperty("line.separator");
        while ((inputLine = in.readLine()) != null)
        {
            response.append(inputLine + newLine);
        }

        in.close();

        return response.toString();
    }
    catch (Exception e)
    {
        throw new RuntimeException(e);
    }
}

3

Ecco la bella risposta di Jeanne, ma racchiusa in una funzione ordinata per i muppet come me:

private static String getUrl(String aUrl) throws MalformedURLException, IOException
{
    String urlData = "";
    URL urlObj = new URL(aUrl);
    URLConnection conn = urlObj.openConnection();
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) 
    {
        urlData = reader.lines().collect(Collectors.joining("\n"));
    }
    return urlData;
}

0

URL a String in Java puro

Chiamata di esempio

 String str = getStringFromUrl("YourUrl");

Implementazione

È possibile utilizzare il metodo descritto in questa risposta, su Come leggere l'URL su un InputStream e combinarlo con questa risposta su Come leggere InputStream su String .

Il risultato sarà qualcosa di simile

public String getStringFromUrl(URL url) throws IOException {
        return inputStreamToString(urlToInputStream(url,null));
}

public String inputStreamToString(InputStream inputStream) throws IOException {
    try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }

        return result.toString(UTF_8);
    }
}

private InputStream urlToInputStream(URL url, Map<String, String> args) {
    HttpURLConnection con = null;
    InputStream inputStream = null;
    try {
        con = (HttpURLConnection) url.openConnection();
        con.setConnectTimeout(15000);
        con.setReadTimeout(15000);
        if (args != null) {
            for (Entry<String, String> e : args.entrySet()) {
                con.setRequestProperty(e.getKey(), e.getValue());
            }
        }
        con.connect();
        int responseCode = con.getResponseCode();
        /* By default the connection will follow redirects. The following
         * block is only entered if the implementation of HttpURLConnection
         * does not perform the redirect. The exact behavior depends to 
         * the actual implementation (e.g. sun.net).
         * !!! Attention: This block allows the connection to 
         * switch protocols (e.g. HTTP to HTTPS), which is <b>not</b> 
         * default behavior. See: /programming/1884230 
         * for more info!!!
         */
        if (responseCode < 400 && responseCode > 299) {
            String redirectUrl = con.getHeaderField("Location");
            try {
                URL newUrl = new URL(redirectUrl);
                return urlToInputStream(newUrl, args);
            } catch (MalformedURLException e) {
                URL newUrl = new URL(url.getProtocol() + "://" + url.getHost() + redirectUrl);
                return urlToInputStream(newUrl, args);
            }
        }
        /*!!!!!*/

        inputStream = con.getInputStream();
        return inputStream;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Professionisti

  • È pura java

  • Può essere facilmente migliorato aggiungendo diverse intestazioni (invece di passare un oggetto null, come nell'esempio sopra), autenticazione, ecc.

  • È supportata la gestione di switch di protocollo

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.