Làm cách nào để lấy nội dung trang web từ WebView?


86

Trên Android, tôi có một WebViewtrang đang hiển thị.

Làm cách nào để lấy nguồn trang mà không yêu cầu lại trang?

Có vẻ như nó WebViewnên có một số loại getPageSource()phương thức trả về một chuỗi, nhưng than ôi nó không.

Nếu tôi bật JavaScript, thì JavaScript thích hợp để đưa vào lệnh gọi này để lấy nội dung là gì?

webview.loadUrl("javascript:(function() { " +  
    "document.getElementsByTagName('body')[0].style.color = 'red'; " +  
    "})()");  

sử dụng jquery script và giao diện js để lấy nội dung html từ webview window.interface.processHTML ($ (\ "body \"). html ());
DroidBot


Rõ ràng bạn có thể nhận được phản hồi trong HTML bằng cách sử dụng Yêu cầu HTTP, nhưng nếu một số trang yêu cầu tải dữ liệu bài đăng (chẳng hạn như thông tin đăng nhập của người dùng, v.v.), thì cách tiếp cận này sẽ không thành công. Tôi nghĩ đây là cách nên làm vì nếu bạn có thể làm điều đó, bạn có thể tạo ứng dụng Android của riêng mình cho bất kỳ trang web nào và điều đó thật tệ!

Câu trả lời:


161

Tôi biết đây là một câu trả lời muộn, nhưng tôi đã tìm thấy câu hỏi này vì tôi đã gặp vấn đề tương tự. Tôi nghĩ rằng tôi đã tìm thấy câu trả lời trong bài đăng này trên lexandera.com. Đoạn mã dưới đây về cơ bản là bản cắt và dán từ trang web. Nó dường như làm các thủ thuật.

final Context myApp = this;

/* An instance of this class will be registered as a JavaScript interface */
class MyJavaScriptInterface
{
    @JavascriptInterface
    @SuppressWarnings("unused")
    public void processHTML(String html)
    {
        // process the html as needed by the app
    }
}

final WebView browser = (WebView)findViewById(R.id.browser);
/* JavaScript must be enabled if you want it to work, obviously */
browser.getSettings().setJavaScriptEnabled(true);

/* Register a new JavaScript interface called HTMLOUT */
browser.addJavascriptInterface(new MyJavaScriptInterface(), "HTMLOUT");

/* WebViewClient must be set BEFORE calling loadUrl! */
browser.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url)
    {
        /* This call inject JavaScript into the page which just finished loading. */
        browser.loadUrl("javascript:window.HTMLOUT.processHTML('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");
    }
});

/* load a web page */
browser.loadUrl("http://lexandera.com/files/jsexamples/gethtml.html");

6
Lưu ý rằng đây có thể không phải là HTML thô của trang; nội dung trang có thể đã thay đổi động thông qua JavaScript trước khi onPageFinished()được thực thi.
Paul Lammertsma

3
Thật tuyệt, nhưng việc gọi phương thức browser.loadUrltrong onPageFinishedsẽ onPageFinishedbị gọi lại. Bạn có thể muốn kiểm tra xem đó có phải là cuộc gọi đầu tiên onPageFinishedhay không trước khi gọi browser.loadUrl.
Yi H.

Cảm ơn @Blundell Nó đã làm việc với tôi. Tôi muốn biết làm thế nào điều này có thể được triển khai như một dịch vụ . Vì là một dịch vụ không có bố cục và webview để lưu trữ kết quả. Có cách nào để đưa dữ liệu vào một số đối tượng khác với webView để chúng ta có thể đặt javascript để lấy mã html kết quả không?
Totalys

@Totalys điều đó thậm chí còn dễ dàng hơn String html = new Scanner(new DefaultHttpClient().execute(new HttpGet("www.the url")).getEntity().getContent(), "UTF-8").useDelimiter("\\A").next();(viết tắt để phù hợp với nhận xét :-))
Blundell

1
Đừng quên chèn runOnUiThread (new Runnable () {... vào public void processHTML.
CoolMind

34

Theo vấn đề 12987 , câu trả lời của Blundell bị lỗi (ít nhất là trên máy ảo 2.3 của tôi). Thay vào đó, tôi chặn một cuộc gọi đến console.log bằng một tiền tố đặc biệt:

// intercept calls to console.log
web.setWebChromeClient(new WebChromeClient() {
    public boolean onConsoleMessage(ConsoleMessage cmsg)
    {
        // check secret prefix
        if (cmsg.message().startsWith("MAGIC"))
        {
            String msg = cmsg.message().substring(5); // strip off prefix

            /* process HTML */

            return true;
        }

        return false;
    }
});

// inject the JavaScript on page load
web.setWebViewClient(new WebViewClient() {
    public void onPageFinished(WebView view, String address)
    {
        // have the page spill its guts, with a secret prefix
        view.loadUrl("javascript:console.log('MAGIC'+document.getElementsByTagName('html')[0].innerHTML);");
    }
});

web.loadUrl("http://www.google.com");

17

Đây là câu trả lời dựa trên jluckyiv's , nhưng tôi nghĩ tốt hơn và đơn giản hơn nếu thay đổi Javascript như sau.

browser.loadUrl("javascript:HTMLOUT.processHTML(document.documentElement.outerHTML);");

6

Bạn đã xem xét việc tìm nạp HTML riêng biệt rồi tải nó vào chế độ xem web chưa?

String fetchContent(WebView view, String url) throws IOException {
    HttpClient httpClient = new DefaultHttpClient();
    HttpGet get = new HttpGet(url);
    HttpResponse response = httpClient.execute(get);
    StatusLine statusLine = response.getStatusLine();
    int statusCode = statusLine.getStatusCode();
    HttpEntity entity = response.getEntity();
    String html = EntityUtils.toString(entity); // assume html for simplicity
    view.loadDataWithBaseURL(url, html, "text/html", "utf-8", url); // todo: get mime, charset from entity
    if (statusCode != 200) {
        // handle fail
    }
    return html;
}

2
Điều này sẽ không mang theo cookie.
Keith Adler

1
Cách tiếp cận này trigger CAPTCHA thoại
Hector

4

Tôi đã cố gắng làm cho điều này hoạt động bằng cách sử dụng mã từ câu trả lời của @ jluckyiv nhưng tôi phải thêm chú thích @JavascriptInterface vào phương thức processHTML trong MyJavaScriptInterface.

class MyJavaScriptInterface
{
    @SuppressWarnings("unused")
    @JavascriptInterface
    public void processHTML(String html)
    {
        // process the html as needed by the app
    }
}

1

Bạn cũng cần chú thích phương thức bằng @JavascriptInterface nếu targetSdkVersion của bạn> = 17 - vì có các yêu cầu bảo mật mới trong SDK 17, tức là tất cả các phương thức javascript phải được chú thích bằng @JavascriptInterface. Nếu không, bạn sẽ thấy lỗi như: Uncaught TypeError: Object [object Object] không có phương thức 'processHTML' tại null: 1


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.