WebViewからWebページのコンテンツを取得するにはどうすればよいですか?


86

AndroidにWebViewは、ページを表示しているがあります。

ページを再度リクエストせずにページソースを取得するにはどうすればよいですか?

そうですWebViewのいくつかの種類が必要getPageSource()文字列を返すメソッドを、悲しいかなそれはしていません。

JavaScriptを有効にした場合、コンテンツを取得するためにこの呼び出しに入れる適切なJavaScriptは何ですか?

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

jqueryスクリプトとjsインターフェイスを使用して、webview window.interface.processHTML($(\ "body \")。html());からhtmlコンテンツを取得します。
droidBot 2013年


HTTPリクエストを使用してHTMLで応答を取得できることは明らかですが、一部のページでPOSTデータをロードする必要がある場合(ユーザー資格情報など)、このアプローチは単に失敗します。もしあなたがそれをすることができれば、あなたはおそらくどんなウェブサイトのためにあなた自身のアンドロイドアプリを作ることができるでしょう、そしてそれはひどいでしょう!

回答:


161

これは遅い答えだと思いますが、同じ問題があったのでこの質問を見つけました。lexandera.comのこの投稿で答えを見つけたと思います。以下のコードは、基本的にサイトからのカットアンドペーストです。それはトリックをするようです。

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
これはページの生のHTMLではない可能性があることに注意してください。ページのコンテンツonPageFinished()は、実行前にJavaScriptを介して動的に変更された可能性があります。
Paul Lammertsma 2011

3
それは素晴らしいことだが、メソッドを呼び出すbrowser.loadUrlには、onPageFinished原因となりonPageFinished、再び呼び出されます。を呼び出すonPageFinished前に、それがの最初の呼び出しであるかどうかを確認することをお勧めしbrowser.loadUrlます。
Yi H.

ありがとう@Blundellそれは私に働いた。これをサービスとしてどのように実装できるか知りたいの ですが。結果を保存するためのレイアウトとWebビューのないサービスです。webViewとは異なる他のオブジェクトにデータを配置して、JavaScriptを配置して結果のhtmlコードを取得できるようにする方法はありますか?
Totalys 2014

@Totalysはさらに簡単ですString html = new Scanner(new DefaultHttpClient().execute(new HttpGet("www.the url")).getEntity().getContent(), "UTF-8").useDelimiter("\\A").next();(コメントに収まるように省略されています:
Blundell

1
runOnUiThreadを挿入することを忘れないでください(新しいRunnableを(){...公共のボイドprocessHTMLに。
CoolMind

34

パー問題12987、ブランデルの答えは(少なくとも私の2.3 VM上で)クラッシュします。代わりに、特別なプレフィックスを付けてconsole.logへの呼び出しをインターセプトします。

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

これはjluckyivに基づく回答ですが、Javascriptを次のように変更する方が簡単だと思います。

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

6

HTMLを個別にフェッチして、それをWebビューにロードすることを検討しましたか?

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
これはクッキーを運びません。
キースアドラー2015年

1
このアプローチはCAPTCHAダイアログをトリガーします
Hector

4

@jluckyivの回答のコードを使用してこれを機能させることができましたが、MyJavaScriptInterfaceのprocessHTMLメソッドに@JavascriptInterfaceアノテーションを追加する必要がありました。

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

1

また、targetSdkVersionが> = 17の場合は、メソッドに@JavascriptInterfaceアノテーションを付ける必要があります。SDK17には新しいセキュリティ要件があるためです。つまり、すべてのjavascriptメソッドに@JavascriptInterfaceアノテーションを付ける必要があります。それ以外の場合は、次のようなエラーが表示されます。UncaughtTypeError:Object [object Object] has no method'processHTML 'at null:1


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.