Читайте URL-адрес строки в несколько строк кода Java

151

Я пытаюсь найти Java-эквивалент Groovy:

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

Я хочу читать содержимое из URL в строку. Я не хочу загрязнять свой код буферизованными потоками и циклами для такой простой задачи. Я посмотрел в HttpClient Apache, но я также не вижу одно-двухстрочной реализации.

Помпоний
источник
6
Почему бы просто не создать служебный класс, который инкапсулирует все эти «загрязненные» буферизованные потоки и циклы? Вы также можете использовать этот класс для обработки таких вещей, как закрытие сокета до завершения потока, и для обработки блоков ввода / вывода через медленное соединение. В конце концов, это ОО - инкапсулировать функциональность и скрыть ее от вашего основного класса.
Джонатан Б
1
Это не может быть сделано в одну или две строки.
Турбьёрн Равн Андерсен

Ответы:

130

Теперь, когда прошло некоторое время с момента принятия первоначального ответа, есть лучший подход:

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

Если вы хотите немного более полную реализацию, которая не состоит из одной строки, сделайте это:

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
источник
14
Только не забудьте, что вам нужно позвонить Scanner#close()позже.
Марсело
2
Регулярное выражение \\ A соответствует началу ввода. Это говорит Сканеру о токенизации всего потока, от начала до (нелогичного) следующего начала.
Руна
7
Аккуратно, но не получается, если веб-страница не возвращает содержимого (""). Вы должны String result = scanner.hasNext() ? scanner.next() : "";справиться с этим.
NateS
3
@ccleve было бы полезно добавить сюда импорт, в Java есть несколько сканеров и URL-адресов
kiedysktos
2
@ccleve Вы можете обновить ссылку "Это объясняет \\ A:"?
Имаскар
95

Этот ответ относится к более старой версии Java. Вы можете посмотреть на ответ ccleve.


Вот традиционный способ сделать это:

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

Как предложил @extraneon , ioutils позволяет вам сделать это очень красноречивым способом, который все еще в духе Java:

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

 try {
   System.out.println( IOUtils.toString( in ) );
 } finally {
   IOUtils.closeQuietly(in);
 }
Иосиф Вайсман
источник
5
Вы можете переименовать основной метод, скажем getText, передать строку URL в качестве параметра и получить однострочную строку:String content = URLConnectionReader.getText("http://www.yahoo.com/");
Горан Йович
7
Строка не будет содержать символ завершения строки (из-за использования BufferReader.readLine (), который их удаляет), поэтому она не будет точно содержимым URL.
Бенуа Гедас
@Benoit Guedas, как сохранить разрывы строк?
user1788736
76

Или просто используйте Apache Commons IOUtils.toString(URL url), или вариант, который также принимает параметр кодирования.

Стив
источник
12
+1 Спасибо, это сработало отлично. Одна строка кода И это закрывает поток! Обратите внимание, что IOUtils.toString(URL)не рекомендуется. IOUtils.toString(URL url, String encoding)является предпочтительным.
gMale
1
IOUtils.toString(url, (Charset) null)достичь аналогичного результата.
frankysnow
3
Одна строка кода и десятки мегабайт файлов посторонних классов, которые теперь находятся в вашей среде выполнения. Включение гигантской библиотеки, чтобы избежать написания нескольких (фактически, одной) строки кода, не является хорошим решением.
Джеффри Блатман
1
@JeffreyBlattman, если вы используете его только один раз в своем приложении, это, вероятно, не такое умное решение, но если вы используете его чаще и другие вещи из пакета commons-io, то это может быть снова умное решение. Это также зависит от приложения, которое вы пишете. Если это мобильное или настольное приложение, вы можете дважды подумать о том, чтобы увеличить объем памяти с помощью дополнительных библиотек. Если это серверное приложение, работающее на машине с 64 ГБ ОЗУ, просто проигнорируйте эти 10 МБ - память сегодня дешева и не имеет значения, занимает ли базовый объем 1,5% или 2% от общего объема вашей памяти
ботаник больших данных
24

Теперь, когда прошло больше времени, вот способ сделать это в 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"));
}
Жанна Боярская
источник
При использовании этого примера на http://www.worldcat.org/webservices/catalog/search/opensearchвеб-сервисе я получаю только первые две строки XML.
Ортомала Локни
Ошибка 400 заключается в том, что вам нужен ключ для использования этого веб-сервиса. Проблема в том, что этот веб-сервис отправляет немного xml, затем занимает несколько секунд, чтобы выполнить некоторую обработку, а затем отправляет вторую часть xml. InputStream закрывается в течение интервала, и не весь контент используется. Я решил проблему, используя http-библиотеку apache hc.apache.org/httpcomponents-client-ga
Ortomala Lokni
17

В Java 9 есть еще лучший способ:

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

Как и в оригинальном groovy-примере, предполагается, что содержимое кодировано в кодировке UTF-8. (Если вам нужно что-то более умное, вам нужно создать URLConnection и использовать его для выяснения кодировки.)

Шон Рейли
источник
1
Спасибо, это именно то, что я искал. Его также можно использовать getClass().getResourceAsStream(...)для открытия текстовых файлов внутри банки.
rjh
8

Дополнительный пример использования гуавы:

URL xmlData = ...
String data = Resources.toString(xmlData, Charsets.UTF_8);
takacsot
источник
1
Документы Guava говорят, что ссылка : Обратите внимание, что хотя эти методы используют параметры {@link URL}, они обычно не подходят для HTTP или других ресурсов, не относящихся к classpath
gaal
3

Следующее работает с Java 7/8, защищенными URL-адресами и показывает, как добавить cookie в ваш запрос. Обратите внимание, что это в основном прямая копия этого другого замечательного ответа на этой странице , но добавлен пример файла cookie и пояснение, что он работает и с безопасными URL-адресами ;-)

Если вам необходимо подключиться к серверу с недействительным сертификатом или самозаверяющим сертификатом, это приведет к ошибкам безопасности, если вы не импортируете сертификат. Если вам нужна эта функциональность, вы можете рассмотреть подход, подробно описанный в этом ответе на этот связанный вопрос о StackOverflow.

пример

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

выходы

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

Код

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

Вот прекрасный ответ Джинн, но она обернута в аккуратную функцию для таких кукол, как я:

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 на строку в чистом Java

Пример вызова

 String str = getStringFromUrl("YourUrl");

Реализация

Вы можете использовать метод, описанный в этом ответе, в разделе Как читать URL-адрес для InputStream и комбинировать его с этим ответом в разделе Как читать InputStream для String .

Результат будет примерно таким

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

Pros

  • Это чистая ява

  • Его можно легко улучшить, добавив различные заголовки (вместо передачи нулевого объекта, как в примере выше), аутентификацию и т. Д.

  • Обработка протокольных коммутаторов поддерживается

jschnasse
источник