如何从 WebView 获取网页内容?

在 Android 上,我有一个正在显示页面的 WebView

如何在不再请求页面的情况下获取页面源代码?

看起来 WebView应该有某种返回字符串的 getPageSource()方法,可惜它没有。

如果我启用了 JavaScript,那么在这个调用中放入什么样的 JavaScript 才能获得内容呢?

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

I think I found the answer in this post on lexandera.com. The code below is basically a cut-and-paste from the site. It seems to do the trick.

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

Per issue 12987, Blundell's answer crashes (at least on my 2.3 VM). Instead, I intercept a call to console.log with a special prefix:

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

This is an answer based on jluckyiv's, but I think it is better and simpler to change Javascript as follows.

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

Have you considered fetching the HTML separately, and then loading it into a webview?

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

I managed to get this working using the code from @jluckyiv's answer but I had to add in @JavascriptInterface annotation to the processHTML method in the MyJavaScriptInterface.

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

You also need to annotate the method with @JavascriptInterface if your targetSdkVersion is >= 17 - because there is new security requirements in SDK 17, i.e. all javascript methods must be annotated with @JavascriptInterface. Otherwise you will see error like: Uncaught TypeError: Object [object Object] has no method 'processHTML' at null:1

If you are working on kitkat and above, you can use the chrome remote debugging tools to find all the requests and responses going in and out of your webview and also the the html source code of the page viewed.

https://developer.chrome.com/devtools/docs/remote-debugging