Прочитайте URL-адресу до рядка в декількох рядках коду Java


151

Я намагаюся знайти еквівалент Java до Groovy:

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

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


6
Чому б просто не створити клас корисності, який інкапсулює всі "забруднені" буферизовані потоки та петлі? Ви також можете використовувати цей клас для обробки речей, таких як закриття сокета до завершення потоку, та для обробки блоків вводу / виводу через повільне з'єднання. Зрештою, це OO - інкапсулюйте функціонал і прихойте його від вашого основного класу.
Джонатан Б

1
Це неможливо зробити в одному або двох рядках.
Thorbjørn Ravn Andersen

Відповіді:


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() : "";
    }
}

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/");
Goran Jovic

7
Рядок не буде містити жодного символу завершення рядка (через використання BufferReader.readLine (), який видаляє їх), тому він не буде точно вмістом URL-адреси.
Benoît Guédas

@ Бенуа Ґеда так, як утримати розриви рядків?
користувач1788736

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)досягти подібного результату.
franckysnow

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

Як і в оригінальному грубому прикладі, це передбачає, що вміст закодовано UTF-8. (Якщо вам потрібно щось розумніше, ніж це, вам потрібно створити URL-з'єднання і використовувати його для з'ясування кодування.)


1
Спасибі, саме це я шукав. Його також можна використовувати getClass().getResourceAsStream(...)для відкриття текстових файлів всередині банку.
rjh

8

Додатковий приклад використання Guava:

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

1
Документи Guava зазначають посилання : Зауважте, що хоча ці методи використовують параметри {@link URL}, вони зазвичай не підходять для HTTP або інших
некласових


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

Плюси

  • Це чиста джава

  • Його можна легко покращити, додавши різні заголовки (замість передачі нульового об'єкта, як це робиться у прикладі вище), автентифікацію тощо.

  • Підтримується обробка перемикачів протоколів

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.