Ler url para string em algumas linhas de código java

151

Estou tentando encontrar o equivalente do Java ao Groovy's:

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

Eu quero ler o conteúdo de um URL em string. Não quero poluir meu código com fluxos e loops em buffer para uma tarefa tão simples. Eu olhei no HttpClient do apache, mas também não vejo uma implementação de uma ou duas linhas.

Pomponius
fonte
6
Por que não criar apenas uma classe de utilitário que encapsula todos os fluxos e loops buffer "poluídos"? Você também pode usar essa classe para manipular coisas como o fechamento do soquete antes da conclusão do fluxo e manipular blocos de E / S em uma conexão lenta. Afinal, isso é OO - encapsule a funcionalidade e oculte-a da sua classe principal.
Jonathan B
1
Não pode ser feito em uma ou duas linhas.
Thorbjørn Ravn Andersen

Respostas:

130

Agora que já passou algum tempo desde que a resposta original foi aceita, há uma abordagem melhor:

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

Se você deseja uma implementação um pouco mais completa, que não seja uma única linha, faça o seguinte:

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
fonte
14
Só não esqueça que você precisa ligar Scanner#close()mais tarde.
Marcelo
2
A expressão regular \\ A corresponde ao início da entrada. Isso indica ao Scanner para tokenizar todo o fluxo, do começo ao (ilógico) próximo começo.
Rune
7
Limpo, mas falhará se a página da web não retornar conteúdo (""). Você precisa String result = scanner.hasNext() ? scanner.next() : "";lidar com isso.
NateS 16/03
3
@ccleve seria útil para adicionar as importações aqui, há vários scanners e URLs em Java
kiedysktos
2
@ccleve você pode atualizar o link "Isso explica o \\ A:"?
Imaskar
95

Esta resposta refere-se a uma versão mais antiga do Java. Você pode querer dar uma olhada na resposta de ccleve.


Aqui está a maneira tradicional de fazer isso:

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

Como o @extraneon sugeriu, o ioutils permite que você faça isso de uma maneira muito eloquente que ainda está no espírito do Java:

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

 try {
   System.out.println( IOUtils.toString( in ) );
 } finally {
   IOUtils.closeQuietly(in);
 }
Joseph Weissman
fonte
5
Você pode renomear o método principal para, por exemplo getText, passar a string da URL como parâmetro e ter uma linha única:String content = URLConnectionReader.getText("http://www.yahoo.com/");
Goran Jovic
7
A sequência não conterá nenhum caractere de terminação de linha (devido ao uso de BufferReader.readLine () que os remove), portanto, não será exatamente o conteúdo da URL.
Benoît Guédas
@Benoit Guedas, como manter as quebras de linha?
usar o seguinte comando
76

Ou apenas use o Apache Commons IOUtils.toString(URL url), ou a variante que também aceita um parâmetro de codificação.

Steve
fonte
12
+1 Obrigado, isso funcionou perfeitamente. Uma linha de código E fecha o fluxo! Observe que IOUtils.toString(URL)está obsoleto. IOUtils.toString(URL url, String encoding)é preferível.
gMale
1
IOUtils.toString(url, (Charset) null)para alcançar resultado semelhante.
franckysnow
3
Uma linha de código e dezenas de megabytes de arquivos de classe estranhos que agora estão em seu tempo de execução. Incluir uma biblioteca gigantesca para evitar escrever algumas (na verdade, uma) linha de código não é uma ótima decisão.
Jeffrey Blattman
1
@JeffreyBlattman, se você o estiver usando apenas uma vez no aplicativo, provavelmente não é uma decisão inteligente, mas se você a estiver usando com mais frequência e outras coisas do pacote commons-io, poderá ser uma decisão inteligente novamente. Também depende do aplicativo que você está escrevendo. Se for um aplicativo móvel ou de desktop, você pode pensar duas vezes em inchar o espaço ocupado pela memória com bibliotecas adicionais. Se é um aplicativo de servidor em execução em 64 máquina GB RAM, em seguida, basta ignorar este 10 MB - Memória é barato hoje em dia e se pegada de básica é de 1,5% ou 2% da sua memória total não importa
grande lerdo dados
24

Agora que mais tempo se passou, eis uma maneira de fazê-lo no 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
fonte
Ao usar este exemplo no serviço da http://www.worldcat.org/webservices/catalog/search/opensearchweb, estou recebendo apenas as duas primeiras linhas de xml.
Ortomala Lokni
O erro 400 é porque você precisa de uma chave para usar este serviço da web. O problema é que esse serviço da Web envia um pouco de xml e, em seguida, leva alguns segundos para fazer algum processamento e, em seguida, envia a segunda parte do xml. O InputStream é fechado durante o intervalo e nem todo o conteúdo é consumido. Eu já resolveu o problema usando o http apache componente de biblioteca hc.apache.org/httpcomponents-client-ga
Ortomala Lokni
17

Existe uma maneira ainda melhor a partir do Java 9:

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

Como o exemplo original do groovy, isso pressupõe que o conteúdo seja codificado em UTF-8. (Se você precisar de algo mais inteligente do que isso, crie uma URLConnection e use-a para descobrir a codificação.)

Sean Reilly
fonte
1
Obrigado, era exatamente isso que eu estava procurando. Também pode ser usado getClass().getResourceAsStream(...)para abrir arquivos de texto dentro do jar.
rjh 6/06
8

Exemplo adicional usando o Guava:

URL xmlData = ...
String data = Resources.toString(xmlData, Charsets.UTF_8);
takacsot
fonte
1
Docs goiaba diz ligação : Nota que, apesar de estes métodos utilizam {url @link} parâmetros, eles são geralmente não é apropriado para HTTP ou outros recursos não-classpath
Gaal
3

O seguinte funciona com Java 7/8, URLs seguros e mostra como adicionar um cookie à sua solicitação também. Observe que essa é principalmente uma cópia direta dessa outra ótima resposta nesta página , mas adicionou o exemplo de cookie e esclarecimentos, pois ela também funciona com URLs seguros ;-)

Se você precisar se conectar a um servidor com um certificado inválido ou certificado autoassinado, isso gerará erros de segurança, a menos que você importe o certificado. Se você precisar dessa funcionalidade, considere a abordagem detalhada nesta resposta a esta pergunta relacionada no StackOverflow.

Exemplo

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

saídas

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

Código

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
fonte
3

Aqui está a resposta adorável de Jeanne, mas envolvida em uma função organizada para os muppets como eu:

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

URL para String em Java puro

Chamada de exemplo

 String str = getStringFromUrl("YourUrl");

Implementação

Você pode usar o método descrito nesta resposta, em Como ler URL em um InputStream e combiná-lo com esta resposta em Como ler InputStream em String .

O resultado será algo como

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

Prós

  • É java puro

  • Ele pode ser facilmente aprimorado adicionando cabeçalhos diferentes (em vez de passar um objeto nulo, como no exemplo acima), autenticação etc.

  • O manuseio de switches de protocolo é suportado

jschnasse
fonte