Як отримати вміст веб-сторінки за допомогою WebView?


86

На Android у мене є, WebViewщо відображає сторінку.

Як отримати джерело сторінки без повторного запиту сторінки?

Здається, WebViewповинен бути якийсь getPageSource()метод, який повертає рядок, але, на жаль, цього немає.

Якщо я ввімкну JavaScript, який відповідний JavaScript потрібно вкласти в цей виклик, щоб отримати вміст?

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

використовуйте скрипт jquery та інтерфейс js для отримання вмісту html із веб-перегляду window.interface.processHTML ($ (\ "body \"). html ());
DroidBot


Очевидно, ви можете отримати відповідь у форматі HTML, використовуючи HTTP-запити, але якщо якась сторінка вимагає завантаження даних публікацій (наприклад, облікових даних користувача тощо), цей підхід просто не вдається. Я думаю, що так повинно бути, тому що якби ви могли це зробити, ви, мабуть, можете створити власний додаток для Android для будь-якого веб-сайту, і це було б відмовно!

Відповіді:


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 сторінки; вміст сторінки, можливо, динамічно змінювався через JavaScript до того, як onPageFinished()був виконаний.
Paul Lammertsma

3
Це чудово, але виклик методу browser.loadUrlв onPageFinishedпризведе onPageFinishedдо того, що буде викликаний знову. Можливо, вам захочеться перевірити, чи це перший дзвінок onPageFinishedперед дзвінком browser.loadUrl.
Yi H.

Дякую @Blundell Мені це вдалося. Я хотів би знати, як це можна реалізувати як послугу . Since - це служба без макета та веб-перегляду для зберігання результатів. Чи є спосіб помістити дані в якийсь інший об’єкт, відмінний від webView, щоб ми могли помістити javascript для отримання результуючого HTML-коду?
Totalys

@Totalys, це ще простіше String html = new Scanner(new DefaultHttpClient().execute(new HttpGet("www.the url")).getEntity().getContent(), "UTF-8").useDelimiter("\\A").next();(скорочено, щоб помістити в коментар :-))
Blundell

1
Не забудьте вставити runOnUiThread (new Runnable () {... у публічний процес недійсностіHTML.
CoolMind

34

За питання 12987 , відповідь BLUNDELL в врізається (принаймні на моєму 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 окремо, а потім завантажити його у веб-перегляд?

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
Це не містить файлів cookie.
Кіт Адлер,

1
цей підхід викликає діалог CAPTCHA
Гектор,

4

Мені вдалося отримати цю роботу за допомогою коду з відповіді @ jluckyiv, але мені довелося додати анотацію @JavascriptInterface до методу processHTML в MyJavaScriptInterface.

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

1

Вам також потрібно анотувати метод методом @JavascriptInterface, якщо ваш targetSdkVersion>> 17 - оскільки в SDK 17 існують нові вимоги до безпеки, тобто всі методи javascript повинні бути анотовані @JavascriptInterface. В іншому випадку ви побачите помилку типу: Uncaught TypeError: Object [object Object] не має методу 'processHTML' у null: 1


0

Якщо ви працюєте на kitkat і вище, ви можете використовувати інструменти віддаленої налагодження chrome, щоб знайти всі запити та відповіді, що надходять і виходять із вашого веб-перегляду, а також HTML-код вихідної сторінки переглянутої сторінки.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.