Lesen Sie die URL, um einige Zeilen Java-Code einzugeben

151

Ich versuche, Javas Äquivalent zu Groovys zu finden:

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

Ich möchte Inhalte von einer URL in eine Zeichenfolge lesen. Ich möchte meinen Code für eine so einfache Aufgabe nicht mit gepufferten Streams und Loops verschmutzen. Ich habe mir den HttpClient von Apache angesehen, sehe aber auch keine ein- oder zweizeilige Implementierung.

Pomponius
quelle
6
Warum nicht einfach eine Utility-Klasse erstellen, die alle "verschmutzten" gepufferten Streams und Loops kapselt? Sie können diese Klasse auch verwenden, um Dinge wie das Schließen des Sockets vor Abschluss des Streams und E / A-Blöcke über eine langsame Verbindung zu behandeln. Immerhin ist dies OO - kapseln Sie die Funktionalität und verstecken Sie sie vor Ihrer Hauptklasse.
Jonathan B
1
Dies kann nicht in ein oder zwei Zeilen erfolgen.
Thorbjørn Ravn Andersen

Antworten:

130

Nachdem einige Zeit vergangen ist, seit die ursprüngliche Antwort akzeptiert wurde, gibt es einen besseren Ansatz:

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

Wenn Sie eine etwas umfassendere Implementierung wünschen, bei der es sich nicht um eine einzelne Zeile handelt, gehen Sie folgendermaßen vor:

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
quelle
14
Vergessen Sie nur nicht, dass Sie Scanner#close()später anrufen müssen .
Marcelo
2
Der reguläre Ausdruck \\ A entspricht dem Beginn der Eingabe. Dies weist den Scanner an, den gesamten Stream vom Anfang bis zum (unlogischen) nächsten Anfang zu tokenisieren.
Rune
7
Ordentlich, schlägt aber fehl, wenn die Webseite keinen Inhalt zurückgibt (""). Sie müssen String result = scanner.hasNext() ? scanner.next() : "";damit umgehen.
NateS
3
@ccleve es wäre nützlich, hier Importe hinzuzufügen, es gibt mehrere Scanner und URLs in Java
kiedysktos
2
@ccleve kannst du den Link "Dies erklärt das \\ A:" aktualisieren?
Imaskar
95

Diese Antwort bezieht sich auf eine ältere Version von Java. Vielleicht möchten Sie sich die Antwort von ccleve ansehen.


Hier ist der traditionelle Weg, dies zu tun:

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

Wie @extraneon vorgeschlagen hat, können Sie dies mit ioutils auf eine sehr beredte Weise tun, die immer noch im Java-Geist ist:

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

 try {
   System.out.println( IOUtils.toString( in ) );
 } finally {
   IOUtils.closeQuietly(in);
 }
Joseph Weissman
quelle
5
Sie können die Hauptmethode umbenennen getText, um beispielsweise eine URL-Zeichenfolge als Parameter zu übergeben und einen Einzeiler zu haben:String content = URLConnectionReader.getText("http://www.yahoo.com/");
Goran Jovic
7
Die Zeichenfolge enthält kein Zeilenabschlusszeichen (aufgrund der Verwendung von BufferReader.readLine (), mit der sie entfernt werden), sodass es sich nicht genau um den Inhalt der URL handelt.
Benoît Guédas
@ Benoit Guedas also, wie man die Zeilenumbrüche hält?
user1788736
76

Oder verwenden Sie einfach Apache Commons IOUtils.toString(URL url) oder die Variante, die auch einen Codierungsparameter akzeptiert.

Steve
quelle
12
+1 Danke, das hat perfekt funktioniert. Eine Codezeile UND es schließt den Stream! Beachten Sie, dass dies IOUtils.toString(URL)veraltet ist. IOUtils.toString(URL url, String encoding)Ist bevorzugt.
gMale
1
IOUtils.toString(url, (Charset) null)um ein ähnliches Ergebnis zu erzielen.
Franckysnow
3
Eine Codezeile und mehrere zehn Megabyte fremde Klassendateien, die sich jetzt in Ihrer Laufzeit befinden. Das Einfügen einer riesigen Bibliothek, um das Schreiben einiger (tatsächlich einer) Codezeile zu vermeiden, ist keine gute Entscheidung.
Jeffrey Blattman
1
@JeffreyBlattman Wenn Sie es nur einmal in Ihrer Anwendung verwenden, ist es wahrscheinlich keine so intelligente Entscheidung, aber wenn Sie es häufiger und andere Dinge aus dem Commons-Io-Paket verwenden, ist es möglicherweise wieder eine intelligente Entscheidung. Dies hängt auch von der Anwendung ab, die Sie schreiben. Wenn es sich um eine mobile oder Desktop-App handelt, sollten Sie zweimal überlegen, ob Sie den Speicherbedarf mit zusätzlichen Bibliotheken aufblähen möchten. Wenn es sich um eine Serveranwendung handelt, die auf einem 64-GB-RAM-Computer ausgeführt wird, ignorieren Sie diese 10 MB einfach - Speicher ist heutzutage billig und es spielt keine Rolle, ob der grundlegende Footprint 1,5% oder 2% Ihres gesamten Speichers beträgt
Big-Data-Nerd
24

Nachdem mehr Zeit vergangen ist, können Sie dies in Java 8 folgendermaßen tun:

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
quelle
Wenn http://www.worldcat.org/webservices/catalog/search/opensearchich dieses Beispiel im Webservice verwende, erhalte ich nur die ersten beiden Zeilen von XML.
Ortomala Lokni
Der Fehler 400 liegt daran, dass Sie einen Schlüssel benötigen, um diesen Webservice zu verwenden. Das Problem ist, dass dieser Webservice ein bisschen XML sendet, dann einige Sekunden braucht, um etwas zu verarbeiten, und dann den zweiten Teil der XML sendet. Der InputStream wird während des Intervalls geschlossen und nicht der gesamte Inhalt wird verbraucht. Ich habe das Problem mit der http-Komponente Apache-Bibliothek hc.apache.org/httpcomponents-client-ga
Ortomala Lokni
17

Ab Java 9 gibt es einen noch besseren Weg:

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

Wie im ursprünglichen groovigen Beispiel wird davon ausgegangen, dass der Inhalt UTF-8-codiert ist. (Wenn Sie etwas Klügeres benötigen, müssen Sie eine URLConnection erstellen und diese verwenden, um die Codierung herauszufinden.)

Sean Reilly
quelle
1
Danke, genau das habe ich gesucht. Es kann auch getClass().getResourceAsStream(...)zum Öffnen von Textdateien im Glas verwendet werden.
6.
8

Zusätzliches Beispiel mit Guava:

URL xmlData = ...
String data = Resources.toString(xmlData, Charsets.UTF_8);
Takacsot
quelle
1
In den Guava-Dokumenten heißt es : Link : Beachten Sie, dass diese Methoden zwar {@link URL} -Parameter verwenden, jedoch normalerweise nicht für HTTP- oder andere Ressourcen außerhalb des Klassenpfads geeignet sind
11.
3

Das Folgende funktioniert mit Java 7/8, sicheren URLs und zeigt, wie Sie Ihrer Anfrage auch ein Cookie hinzufügen können. Beachten Sie, dass dies meistens eine direkte Kopie dieser anderen großartigen Antwort auf dieser Seite ist , aber das Cookie-Beispiel hinzugefügt und klargestellt wurde, dass es auch mit sicheren URLs funktioniert ;-)

Wenn Sie eine Verbindung zu einem Server mit einem ungültigen Zertifikat oder einem selbstsignierten Zertifikat herstellen müssen, werden Sicherheitsfehler ausgegeben, sofern Sie das Zertifikat nicht importieren. Wenn Sie diese Funktionalität benötigen, können Sie den in dieser Antwort auf diese verwandte Frage zu StackOverflow beschriebenen Ansatz in Betracht ziehen .

Beispiel

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

Ausgänge

<!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
quelle
3

Hier ist Jeannes schöne Antwort, aber für Muppets wie mich eine ordentliche Funktion:

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
quelle
0

URL zu String in reinem Java

Beispielaufruf

 String str = getStringFromUrl("YourUrl");

Implementierung

Sie können die in dieser Antwort beschriebene Methode unter Lesen der URL zu einem InputStream verwenden und mit dieser Antwort unter Lesen der Eingabe von InputStream in String kombinieren .

Das Ergebnis wird so etwas wie sein

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

Vorteile

  • Es ist reines Java

  • Es kann leicht erweitert werden, indem verschiedene Header hinzugefügt werden (anstatt ein Nullobjekt zu übergeben, wie im obigen Beispiel), Authentifizierung usw.

  • Die Handhabung von Protokollschaltern wird unterstützt

jschnasse
quelle