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'; " +  
    "})()");  

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

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

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

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

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

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


-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


Pertanyaan tentang mengakses secara terprogram. Bisakah Anda menjelaskan bagaimana posting Anda berguna?
Ajay Prajapati
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.