Bagaimana cara mendapatkan konten halaman web dari WebView?

86

Di Android, saya memiliki WebViewyang menampilkan halaman.

Bagaimana cara mendapatkan sumber halaman tanpa meminta halaman itu lagi?

Tampaknya WebViewharus memiliki semacam getPageSource()metode yang mengembalikan string, tetapi sayangnya tidak.

Jika saya mengaktifkan JavaScript, apa JavaScript yang sesuai untuk dimasukkan ke dalam panggilan ini untuk mendapatkan konten?

webview.loadUrl("javascript:(function() { " +  
    "document.getElementsByTagName('body')[0].style.color = 'red'; " +  
    "})()");  
gregm
sumber
gunakan skrip jquery dan antarmuka js untuk mendapatkan konten html dari jendela tampilan web.interface.processHTML ($ (\ "body \"). html ());
DroidBot
Anda jelas bisa mendapatkan respon dalam HTML menggunakan Permintaan HTTP, tetapi jika beberapa halaman membutuhkan data posting untuk dimuat (seperti misalnya kredensial pengguna dll), pendekatan ini gagal. Saya pikir begitulah seharusnya karena jika Anda bisa melakukannya, Anda mungkin bisa membuat aplikasi android Anda sendiri untuk situs web apa pun dan itu akan payah!

Jawaban:

162

Saya tahu ini adalah jawaban yang terlambat, tetapi saya menemukan pertanyaan ini karena saya memiliki masalah yang sama. Saya rasa saya menemukan jawabannya dalam posting ini di lexandera.com. Kode di bawah ini pada dasarnya adalah potongan-dan-tempel dari situs. Tampaknya berhasil.

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");
jluckyiv
sumber
6
Berhati-hatilah karena ini mungkin bukan HTML mentah halaman; konten halaman mungkin telah berubah secara dinamis melalui JavaScript sebelum onPageFinished()dieksekusi.
Paul Lammertsma
3
Ini bagus, tapi memanggil metode browser.loadUrldalam onPageFinishedakan menyebabkan onPageFinisheddisebut lagi. Anda mungkin ingin memeriksa apakah ini panggilan pertama onPageFinishedatau bukan sebelum menelepon browser.loadUrl.
Yi H.
Terima kasih @Blundell Itu berhasil untuk saya. Saya ingin tahu bagaimana ini dapat diterapkan sebagai layanan . Karena merupakan layanan tanpa tata letak dan tampilan web untuk menyimpan hasil. Apakah ada cara untuk meletakkan data di objek lain yang berbeda dari webView sehingga kita bisa meletakkan javascript untuk mendapatkan kode html yang dihasilkan?
Totalys
@Totalys itu lebih mudah String html = new Scanner(new DefaultHttpClient().execute(new HttpGet("www.the url")).getEntity().getContent(), "UTF-8").useDelimiter("\\A").next();(disingkat agar sesuai dengan komentar :-))
Blundell
1
Jangan lupa untuk memasukkan runOnUiThread (new Runnable () {... ke dalam public void processHTML.
CoolMind
34

Per masalah 12987 , jawaban Blundell lumpuh (setidaknya di VM 2.3 saya). Sebagai gantinya, saya mencegat panggilan ke console.log dengan awalan khusus:

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

Ini adalah jawaban berdasarkan jluckyiv's , tapi menurut saya lebih baik dan lebih sederhana untuk mengubah Javascript sebagai berikut.

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

Pernahkah Anda mempertimbangkan untuk mengambil HTML secara terpisah, lalu memuatnya ke dalam tampilan 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;
}
larham1
sumber
2
Ini tidak akan membawa cookie.
Keith Adler
1
pendekatan ini memicu dialog CAPTCHA
Hector
4

Saya berhasil mendapatkan ini bekerja menggunakan kode dari jawaban @ jluckyiv tetapi saya harus menambahkan anotasi @JavascriptInterface ke metode processHTML di MyJavaScriptInterface.

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

Anda juga perlu menganotasi metode dengan @JavascriptInterface jika targetSdkVersion Anda> = 17 - karena ada persyaratan keamanan baru di SDK 17, yaitu semua metode javascript harus dianotasi dengan @JavascriptInterface. Jika tidak, Anda akan melihat kesalahan seperti: Uncaught TypeError: Object [object Object] tidak memiliki metode 'processHTML' pada null: 1

javauser71
sumber
-1

Jika Anda bekerja dengan kitkat dan yang lebih baru, Anda dapat menggunakan alat debugging jarak jauh chrome untuk menemukan semua permintaan dan tanggapan yang masuk dan keluar dari tampilan web Anda dan juga kode sumber html dari laman yang dilihat.

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

onusopus
sumber
Pertanyaan tentang mengakses secara terprogram. Bisakah Anda menjelaskan bagaimana posting Anda berguna?
Ajay Prajapati