Lire l'URL en chaîne en quelques lignes de code java

151

J'essaye de trouver l'équivalent Java de Groovy:

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

Je veux lire le contenu d'une URL en chaîne. Je ne veux pas polluer mon code avec des flux et des boucles tamponnés pour une tâche aussi simple. J'ai regardé dans HttpClient d'Apache mais je ne vois pas non plus d'implémentation en une ou deux lignes.

Pomponius
la source
6
Pourquoi ne pas simplement créer une classe utilitaire qui encapsule tous ces flux et boucles tamponnés «pollués»? Vous pouvez également utiliser cette classe pour gérer des choses comme la fermeture du socket avant la fin du flux et pour gérer les blocs d'E / S sur une connexion lente. Après tout, c'est OO - encapsulez la fonctionnalité et cachez-la de votre classe principale.
Jonathan B
1
Cela ne peut pas être fait en une ou deux lignes.
Thorbjørn Ravn Andersen

Réponses:

130

Maintenant qu'un certain temps s'est écoulé depuis que la réponse originale a été acceptée, il existe une meilleure approche:

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

Si vous voulez une implémentation légèrement plus complète, qui ne soit pas une seule ligne, procédez comme suit:

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() : "";
    }
}
ccleve
la source
14
N'oubliez pas que vous devez appeler Scanner#close()plus tard.
Marcelo
2
L'expression régulière \\ A correspond au début de l'entrée. Cela indique à Scanner de tokeniser tout le flux, du début au prochain début (illogique).
Rune
7
Neat, mais échoue si la page Web ne renvoie aucun contenu (""). Vous devez String result = scanner.hasNext() ? scanner.next() : "";gérer cela.
NateS
3
@ccleve, il serait utile d'ajouter des importations ici, il existe plusieurs scanners et URL en Java
kiedysktos
2
@ccleve pouvez-vous mettre à jour le lien "Ceci explique le \\ A:"?
Imaskar
95

Cette réponse fait référence à une ancienne version de Java. Vous voudrez peut-être regarder la réponse de ccleve.


Voici la manière traditionnelle de procéder:

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);
    }
}

Comme @extraneon l'a suggéré, ioutils vous permet de le faire d'une manière très éloquente et toujours dans l'esprit Java:

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

 try {
   System.out.println( IOUtils.toString( in ) );
 } finally {
   IOUtils.closeQuietly(in);
 }
Joseph Weissman
la source
5
Vous pouvez renommer la méthode principale pour, par exemple getText, passer la chaîne d'URL en tant que paramètre et avoir une ligne unique:String content = URLConnectionReader.getText("http://www.yahoo.com/");
Goran Jovic
7
La chaîne ne contiendra aucun caractère de fin de ligne (à cause de l'utilisation de BufferReader.readLine () qui les supprime), donc ce ne sera pas exactement le contenu de l'URL.
Benoît Guédas
@Benoit Guedas alors comment garder les sauts de ligne?
user1788736
76

Ou utilisez simplement Apache Commons IOUtils.toString(URL url), ou la variante qui accepte également un paramètre d'encodage.

Steve
la source
12
+1 Merci, cela a parfaitement fonctionné. Une ligne de code ET ça ferme le flux! Notez que IOUtils.toString(URL)c'est obsolète. IOUtils.toString(URL url, String encoding)est préféré.
gMale
1
IOUtils.toString(url, (Charset) null)pour atteindre un résultat similaire.
franckysnow
3
Une ligne de code et des dizaines de mégaoctets de fichiers de classe superflus qui se trouvent maintenant dans votre environnement d'exécution. Inclure une gigantesque bibliothèque pour éviter d'écrire quelques (en fait, une) ligne de code n'est pas une bonne décision.
Jeffrey Blattman
1
@JeffreyBlattman si vous ne l'utilisez qu'une seule fois dans votre application, ce n'est probablement pas une décision si intelligente, mais si vous l'utilisez plus fréquemment et d'autres choses du package commons-io, cela pourrait être à nouveau une décision intelligente. Cela dépend également de l'application que vous écrivez. S'il s'agit d'une application mobile ou de bureau, vous pourriez réfléchir à deux fois avant de gonfler l'empreinte mémoire avec des bibliothèques supplémentaires. S'il s'agit d'une application serveur fonctionnant sur une machine de 64 Go de RAM, ignorez simplement ces 10 Mo - la mémoire est bon marché de nos jours et si l'empreinte de base est de 1,5% ou 2% de votre mémoire totale n'a pas d'importance
nerd du big data
24

Maintenant que plus de temps s'est écoulé, voici un moyen de le faire en 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"));
}
Jeanne Boyarsky
la source
Lorsque vous utilisez cet exemple sur le service http://www.worldcat.org/webservices/catalog/search/opensearchWeb, je n'obtiens que les deux premières lignes de xml.
Ortomala Lokni
L'erreur 400 est due au fait que vous avez besoin d'une clé pour utiliser ce service Web. Le problème est que ce webservice envoie un peu de xml puis prend plusieurs secondes pour effectuer un certain traitement, puis envoie la deuxième partie du xml. Le InputStream est fermé pendant l'intervalle et tout le contenu n'est pas consommé. J'ai résolu le problème en utilisant la bibliothèque apache du composant http hc.apache.org/httpcomponents-client-ga
Ortomala Lokni
17

Il existe un moyen encore meilleur à partir de Java 9:

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

Comme l'exemple original groovy, cela suppose que le contenu est encodé en UTF-8. (Si vous avez besoin de quelque chose de plus intelligent que cela, vous devez créer une URLConnection et l'utiliser pour comprendre l'encodage.)

Sean Reilly
la source
1
Merci, c'était exactement ce que je cherchais. Il peut également être utilisé avec getClass().getResourceAsStream(...)pour ouvrir des fichiers texte à l'intérieur du fichier jar.
rjh
8

Exemple supplémentaire utilisant Guava:

URL xmlData = ...
String data = Resources.toString(xmlData, Charsets.UTF_8);
Takacsot
la source
1
Guava docs dit link : notez que même si ces méthodes utilisent des paramètres {@link URL}, elles ne sont généralement pas appropriées pour HTTP ou d'autres ressources non classpath
gaal
3

Ce qui suit fonctionne avec Java 7/8, des URL sécurisées et montre comment ajouter un cookie à votre demande également. Notez qu'il s'agit principalement d'une copie directe de cette autre excellente réponse sur cette page , mais a ajouté l'exemple de cookie, et une clarification en ce sens qu'il fonctionne également avec des URL sécurisées ;-)

Si vous devez vous connecter à un serveur avec un certificat non valide ou un certificat auto-signé, cela générera des erreurs de sécurité, sauf si vous importez le certificat. Si vous avez besoin de cette fonctionnalité, vous pouvez envisager l'approche détaillée dans cette réponse à cette question associée sur StackOverflow.

Exemple

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

les sorties

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

Code

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);
    }
}
Brad Parks
la source
3

Voici la belle réponse de Jeanne, mais enveloppée dans une fonction bien rangée pour les marionnettes comme moi:

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;
}
Dave
la source
0

URL vers chaîne en Java pur

Exemple d'appel

 String str = getStringFromUrl("YourUrl");

la mise en oeuvre

Vous pouvez utiliser la méthode décrite dans cette réponse, sur Comment lire une URL vers un InputStream et la combiner avec cette réponse sur Comment lire InputStream vers une chaîne .

Le résultat sera quelque chose comme

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);
    }
}

Avantages

  • C'est du pur java

  • Il peut être facilement amélioré en ajoutant différents en-têtes (au lieu de passer un objet nul, comme le fait l'exemple ci-dessus), l'authentification, etc.

  • La gestion des commutateurs de protocole est prise en charge

jschnasse
la source