Đọc url để chuỗi trong vài dòng mã java


151

Tôi đang cố gắng tìm Java tương đương với Groovy:

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

Tôi muốn đọc nội dung từ một URL thành chuỗi. Tôi không muốn làm ô nhiễm mã của mình với các luồng và vòng đệm cho một nhiệm vụ đơn giản như vậy. Tôi đã xem xét httpClient của apache nhưng tôi cũng không thấy triển khai một hoặc hai dòng.


6
Tại sao không chỉ tạo một lớp tiện ích gói gọn tất cả các luồng và vòng đệm "ô nhiễm"? Bạn cũng có thể sử dụng lớp đó để xử lý những thứ như đóng ổ cắm trước khi luồng hoàn thành và để xử lý các khối I / O qua kết nối chậm. Rốt cuộc, đây là OO - gói gọn chức năng và ẩn nó khỏi lớp chính của bạn.
Jonathan B

1
Nó không thể được thực hiện trong một hoặc hai dòng.
Thorbjørn Ravn Andersen

Câu trả lời:


130

Bây giờ đã một thời gian trôi qua kể từ khi câu trả lời ban đầu được chấp nhận, có một cách tiếp cận tốt hơn:

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

Nếu bạn muốn triển khai đầy đủ hơn một chút, không phải là một dòng duy nhất, hãy làm điều này:

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
Chỉ cần đừng quên bạn cần gọi Scanner#close()sau.
Marcelo

2
Biểu thức chính quy \ A khớp với đầu của đầu vào. Điều này nói với Scanner để mã hóa toàn bộ luồng, từ đầu đến (phi logic) bắt đầu tiếp theo.
Rune

7
Gọn gàng, nhưng không thành công nếu trang web không trả lại nội dung (""). Bạn cần String result = scanner.hasNext() ? scanner.next() : "";phải xử lý điều đó.
NateS

3
@ccleve sẽ rất hữu ích khi thêm nhập khẩu ở đây, có nhiều Trình quét và URL trong Java
kiedysktos

2
@ccleve bạn có thể cập nhật liên kết "Điều này giải thích cho \ A:"?
Imaskar

95

Câu trả lời này đề cập đến một phiên bản cũ hơn của Java. Bạn có thể muốn xem câu trả lời của ccleve.


Đây là cách truyền thống để làm điều này:

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

Như @extraneon đã đề xuất, ioutils cho phép bạn thực hiện điều này theo một cách rất hùng hồn vẫn còn trong tinh thần Java:

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

 try {
   System.out.println( IOUtils.toString( in ) );
 } finally {
   IOUtils.closeQuietly(in);
 }

5
Bạn có thể đổi tên phương thức chính thành, getTexttruyền chuỗi URL làm tham số và có một lớp lót:String content = URLConnectionReader.getText("http://www.yahoo.com/");
Goran Jovic

7
Chuỗi sẽ không chứa bất kỳ ký tự kết thúc dòng nào (do sử dụng BufferReader.readLine () loại bỏ chúng), do đó, nó sẽ không chính xác là nội dung của URL.
Benoît Guédas

@Benoit Guedas vậy làm thế nào để giữ cho dòng ngắt?
dùng1788736

76

Hoặc chỉ sử dụng Apache Commons IOUtils.toString(URL url)hoặc biến thể cũng chấp nhận tham số mã hóa.


12
+1 Cảm ơn, điều này đã làm việc hoàn hảo. Một dòng mã VÀ nó đóng luồng! Lưu ý rằng IOUtils.toString(URL)không được chấp nhận. IOUtils.toString(URL url, String encoding)được ưa thích.
gMale

1
IOUtils.toString(url, (Charset) null)để đạt được kết quả tương tự.
franckysnow 4/2/2015

3
Một dòng mã và hàng chục megabyte tệp ngoại lai hiện có trong thời gian chạy của bạn. Bao gồm một thư viện khổng lồ để tránh viết một vài dòng mã (thực tế là một) không phải là một quyết định tuyệt vời.
Jeffrey Blattman

1
@JeffreyBlattman nếu bạn chỉ sử dụng một lần trong ứng dụng của mình thì có lẽ đó không phải là một sự phân rã thông minh, nhưng nếu bạn đang sử dụng nó thường xuyên hơn và những thứ khác từ gói commons-io thì đó có thể là một sự phân rã thông minh một lần nữa. Nó cũng phụ thuộc vào ứng dụng bạn đang viết. Nếu đó là một thiết bị di động hoặc máy tính để bàn, bạn có thể nghĩ hai lần về việc làm đầy dấu chân bộ nhớ với các thư viện bổ sung. Nếu đó là một ứng dụng máy chủ chạy trên máy RAM 64 GB, thì hãy bỏ qua 10 MB này - bộ nhớ hiện tại rất rẻ và liệu dấu chân cơ bản là 1,5% hay 2% tổng bộ nhớ của bạn không thành vấn đề
dữ liệu lớn

24

Bây giờ đã có nhiều thời gian hơn trôi qua, đây là một cách để làm điều đó trong 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"));
}

Khi sử dụng ví dụ này trên dịch vụ web http://www.worldcat.org/webservices/catalog/search/opensearch, tôi chỉ nhận được hai dòng xml đầu tiên.
Ortomala Lokni

Lỗi 400 là do bạn cần một khóa để sử dụng dịch vụ web này. Vấn đề là dịch vụ web này gửi một chút xml sau đó mất vài giây để thực hiện một số xử lý và sau đó gửi phần thứ hai của xml. InputStream được đóng trong khoảng thời gian và không phải tất cả nội dung đều được tiêu thụ. Tôi đã giải quyết vấn đề bằng thư viện apache thành phần http hc.apache.org/httpcomponents-client-ga
Ortomala Lokni

17

Có một cách thậm chí tốt hơn kể từ Java 9:

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

Giống như ví dụ Groovy ban đầu, điều này giả định rằng nội dung được mã hóa UTF-8. (Nếu bạn cần thứ gì đó thông minh hơn thế, bạn cần tạo URLConnection và sử dụng nó để tìm ra mã hóa.)


1
Cảm ơn, đây chính xác là những gì tôi đang tìm kiếm. Nó cũng có thể được sử dụng getClass().getResourceAsStream(...)để mở các tệp văn bản bên trong jar.
rjh

8

Ví dụ bổ sung sử dụng ổi:

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

1
Tài liệu ổi nói liên kết : Lưu ý rằng mặc dù các phương thức này sử dụng tham số {@link URL}, nhưng chúng thường không phù hợp với HTTP hoặc các tài nguyên không phân loại khác
gaal


3

Phần sau đây hoạt động với Java 7/8, các url an toàn và cũng chỉ ra cách thêm cookie vào yêu cầu của bạn. Lưu ý rằng đây chủ yếu là một bản sao trực tiếp của câu trả lời tuyệt vời khác này trên trang này , nhưng đã thêm ví dụ về cookie và làm rõ rằng nó cũng hoạt động với các url an toàn ;-)

Nếu bạn cần kết nối với máy chủ có chứng chỉ không hợp lệ hoặc chứng chỉ tự ký, điều này sẽ gây ra lỗi bảo mật trừ khi bạn nhập chứng chỉ. Nếu bạn cần chức năng này, bạn có thể xem xét cách tiếp cận chi tiết trong câu trả lời này cho câu hỏi liên quan này trên StackOverflow.

Thí dụ

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

đầu ra

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

Đây là câu trả lời đáng yêu của Jeanne, nhưng được gói gọn trong một chức năng gọn gàng cho những muppets như tôi:

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 tới Chuỗi trong Java thuần

Cuộc gọi ví dụ

 String str = getStringFromUrl("YourUrl");

Thực hiện

Bạn có thể sử dụng phương pháp được mô tả trong câu trả lời này, về Cách đọc URL cho InputStream và kết hợp nó với câu trả lời này về Cách đọc InputStream thành Chuỗi .

Kết quả sẽ giống như

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

Ưu

  • Nó là java thuần túy

  • Nó có thể dễ dàng được tăng cường bằng cách thêm các tiêu đề khác nhau (thay vì chuyển một đối tượng null, như ví dụ ở trên), xác thực, v.v.

  • Xử lý các chuyển đổi giao thức được hỗ trợ

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.