자바 코드 몇 줄로 문자열을 URL로 읽기


151

Groovy와 동등한 Java를 찾으려고합니다.

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

URL에서 문자열로 내용을 읽고 싶습니다. 그런 간단한 작업을 위해 버퍼 스트림과 루프로 코드를 오염시키고 싶지 않습니다. 아파치의 HttpClient를 살펴 보았지만 한두 줄 구현도 보지 못했습니다.


6
왜 "오염 된"버퍼링 된 스트림과 루프를 모두 캡슐화하는 유틸리티 클래스를 작성하지 않겠습니까? 이 클래스를 사용하여 스트림이 완료되기 전에 소켓 닫기와 같은 것을 처리하고 느린 연결을 통해 I / O 블록을 처리 할 수도 있습니다. 결국 이것은 OO입니다. 기능을 캡슐화하고 기본 클래스에서 숨 깁니다.
Jonathan B

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()나중에 전화해야한다는 것을 잊지 마십시오 .
Marcelo

2
정규식 \\ A는 입력의 시작과 일치합니다. 그러면 시작부터 (비논리적) 다음 시작까지 전체 스트림을 토큰 화하도록 스캐너에 지시합니다.
Rune

7
깔끔하지만 웹 페이지가 내용 ( "")을 반환하지 않으면 실패합니다. 당신은 String result = scanner.hasNext() ? scanner.next() : "";그것을 처리 해야 합니다.
NateS

3
@ccleve는 자바에서 여러 스캐너 및 URL이 있습니다, 여기에 수입을 추가하는 것이 유용 할 것
kiedysktos

2
@ccleve 링크 "\\ A :"를 업데이트 할 수 있습니까?
Imaskar

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

@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)비슷한 결과에 도달합니다.
franckysnow

3
한 줄의 코드와 현재 런타임에있는 수십 메가 바이트의 외부 클래스 파일. 몇 줄 (실제로 한 줄)의 코드 작성을 피하기 위해 거대한 라이브러리를 포함시키는 것은 큰 결정이 아닙니다.
Jeffrey Blattman 1

1
@JeffreyBlattman 응용 프로그램에서 한 번만 사용하는 경우 스마트 현명한 결정은 아니지만 아마도 자주 사용하고 commons-io 패키지의 다른 것들을 사용하는 경우 다시 똑똑한 결정 일 수 있습니다. 또한 작성중인 응용 프로그램에 따라 다릅니다. 모바일 또는 데스크톱 응용 프로그램이라면 추가 라이브러리로 메모리 공간을 늘리는 것에 대해 두 번 생각할 수 있습니다. 메모리가 요즘 저렴하고 드 기본 풋 프린트 여부를 중요하지 1.5 % 또는 총 메모리의 2 % 않습니다 - 그것은 64기가바이트 RAM 시스템에서 실행중인 서버 응용 프로그램의 경우, 그냥이 10MB의 무시
빅 데이터 괴상한

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의 ​​처음 두 줄만 얻습니다.
Ortomala Lokni

400 오류는이 웹 서비스를 사용하기 위해 키가 필요하기 때문입니다. 문제는이 웹 서비스가 약간의 xml을 보낸 다음 몇 초 동안 처리를 한 다음 xml의 두 번째 부분을 보내는 것입니다. 간격 동안 InputStream이 닫히고 일부 컨텐츠가 사용되는 것은 아닙니다. 나는 HTTP 구성 요소 아파치 라이브러리를 사용하여 문제를 해결 한 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로 인코딩 된 것으로 가정합니다. (그보다 더 영리한 것이 필요하면 URLConnection을 작성하고이를 사용하여 인코딩을 파악해야합니다.)


1
고마워, 이것은 내가 찾던 것입니다. getClass().getResourceAsStream(...)jar 내부의 텍스트 파일을 여는 데 사용할 수도 있습니다 .
rjh

8

구아바를 사용한 추가 예 :

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

1
구아바 문서를 말한다 링크 이러한 방법 {@link URL} 매개 변수를 사용하더라도, 그들은 일반적으로 HTTP 또는 기타 클래스 패스 자원에 적합하지 참고 :
가알


3

다음은 Java 7/8, 보안 URL에서 작동하며 요청에 쿠키를 추가하는 방법도 보여줍니다. 이것은 대부분 이 페이지 에서이 위대한 답변 의 직접적인 사본 이지만 쿠키 예제를 추가하고 보안 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

다음은 Jeanne의 멋진 답변이지만 나와 같은 머펫에 대한 깔끔한 기능에 싸여 있습니다.

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

순수 Java에서 문자열의 URL

호출 예

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

찬성

  • 순수한 자바입니다

  • 다른 헤더 (위의 예와 같이 null 객체를 전달하는 대신), 인증 등을 추가하여 쉽게 향상시킬 수 있습니다.

  • 프로토콜 스위치 처리가 지원됩니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.