Wie bekomme ich HTML-Inhalte aus einer Webansicht?


123

Welches ist die einfachste Methode, um HTML-Code aus einer Webansicht abzurufen? Ich habe verschiedene Methoden von Stackoverflow und Google ausprobiert, kann aber keine genaue Methode finden. Bitte geben Sie einen genauen Weg an.

public class htmldecoder extends Activity implements OnClickListener,TextWatcher
{
TextView txturl;
Button btgo;
WebView wvbrowser;
TextView txtcode;
ImageButton btcode;
LinearLayout llayout;
int flagbtcode;
public void onCreate(Bundle savedInstanceState)
{
            super.onCreate(savedInstanceState);
                setContentView(R.layout.htmldecoder);

    txturl=(TextView)findViewById(R.id.txturl);

    btgo=(Button)findViewById(R.id.btgo);
    btgo.setOnClickListener(this);

    wvbrowser=(WebView)findViewById(R.id.wvbrowser);
    wvbrowser.setWebViewClient(new HelloWebViewClient());
    wvbrowser.getSettings().setJavaScriptEnabled(true);
    wvbrowser.getSettings().setPluginsEnabled(true);
    wvbrowser.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
    wvbrowser.addJavascriptInterface(new MyJavaScriptInterface(),"HTMLOUT");
    //wvbrowser.loadUrl("http://www.google.com");
    wvbrowser.loadUrl("javascript:window.HTMLOUT.showHTML('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");


    txtcode=(TextView)findViewById(R.id.txtcode);
    txtcode.addTextChangedListener(this);

    btcode=(ImageButton)findViewById(R.id.btcode);
    btcode.setOnClickListener(this);

    }

public void onClick(View v)
{
    if(btgo==v)
    {
        String url=txturl.getText().toString();
        if(!txturl.getText().toString().contains("http://"))
        {
            url="http://"+url;
        }
        wvbrowser.loadUrl(url);
        //wvbrowser.loadData("<html><head></head><body><div style='width:100px;height:100px;border:1px red solid;'></div></body></html>","text/html","utf-8");
    }
    else if(btcode==v)
    {
        ViewGroup.LayoutParams params1=wvbrowser.getLayoutParams();
        ViewGroup.LayoutParams params2=txtcode.getLayoutParams();
        if(flagbtcode==1)
        {
            params1.height=200;
            params2.height=220;
            flagbtcode=0;
            //txtcode.setText(wvbrowser.getContentDescription());
        }
        else
        {
            params1.height=420;
            params2.height=0;
            flagbtcode=1;
        }
        wvbrowser.setLayoutParams(params1);
        txtcode.setLayoutParams(params2);

    }
}

public class HelloWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {

        view.loadUrl(url);
        return true;
    }
    /*@Override
    public void onPageFinished(WebView view, String url)
    {
        // This call inject JavaScript into the page which just finished loading. 
        wvbrowser.loadUrl("javascript:window.HTMLOUT.processHTML('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");
    }*/

}
class MyJavaScriptInterface
{
    @SuppressWarnings("unused")
    public void showHTML(String html)
    {

        txtcode.setText(html);
    }
}

public void afterTextChanged(Editable s) {
    // TODO Auto-generated method stub

}

public void beforeTextChanged(CharSequence s, int start, int count,
        int after) {
    // TODO Auto-generated method stub

}

public void onTextChanged(CharSequence s, int start, int before, int count) {
    wvbrowser.loadData("<html><div"+txtcode.getText().toString()+"></div></html>","text/html","utf-8");

}

}

Antworten:


107

Eigentlich hat diese Frage viele Antworten. Hier sind 2 davon:

  • Dies ist fast das gleiche wie deins. Ich denke, wir haben es aus demselben Tutorial erhalten.

public class TestActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.webview);
        final WebView webview = (WebView) findViewById(R.id.browser);
        webview.getSettings().setJavaScriptEnabled(true);
        webview.addJavascriptInterface(new MyJavaScriptInterface(this), "HtmlViewer");

        webview.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                webview.loadUrl("javascript:window.HtmlViewer.showHTML" +
                        "('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
            }
        });

        webview.loadUrl("http://android-in-action.com/index.php?post/" +
                "Common-errors-and-bugs-and-how-to-solve-avoid-them");
    }

    class MyJavaScriptInterface {

        private Context ctx;

        MyJavaScriptInterface(Context ctx) {
            this.ctx = ctx;
        }

        public void showHTML(String html) {
            new AlertDialog.Builder(ctx).setTitle("HTML").setMessage(html)
                    .setPositiveButton(android.R.string.ok, null).setCancelable(false).create().show();
        }

    }
}

Auf diese Weise greifen Sie das HTML durch Javascript. Nicht der schönste Weg, aber wenn Sie Ihre Javascript-Oberfläche haben, können Sie andere Methoden hinzufügen, um sie zu basteln.


  • Eine andere Möglichkeit ist die Verwendung eines HttpClient wie dort .

Die Option, die Sie wählen, hängt meiner Meinung nach auch davon ab, was Sie mit dem abgerufenen HTML-Code tun möchten ...


Wenn Sie diese Zeile ausführen, verhält sich webview.loadUrl("javascript:window.HtmlViewer.showHTML" + "('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");das Programm wie die Funktion finish () und beendet diese Aktivität. Warum? Wie kann man sie lösen?

7
webview.addJavascriptInterface Funktioniert nur mit Jelly Beans und einer niedrigeren Version.
20.

32
Zwei wichtige Änderungen am obigen Code für Jellybean und höher: 1. Entfernen Sie "Fenster". aus der Zeile webview.loadUrl - Die Javascript-Oberfläche wird beim Targeting von Jellybean anders angehängt. 2. Setzen Sie @JavascriptInterface vor "public void showHTML" - dies ist erforderlich, da es ein Sicherheitsrisiko darstellt, nicht nur das Aufrufen bestimmter Methoden zuzulassen.
karlbecker_com

1
Funktioniert immer noch nicht für mich (5.1.1). Wenn ich MyJavaScriptInterface (mit @ karlbecker_com-Hinweisen) hinzufüge, wenn ich auf ein geladenes Seitensystem klicke, werde ich aufgefordert, den Browser auszuwählen. Wenn ich das entferne, werde ich nicht mehr gefragt.
Makalele

1
Hier habe ich das Remote-Debugging aktiviert Uncaught ReferenceError: HtmlViewer is not defined, egal mit oder ohne@JavascriptInterface
MewX

55

In KitKat und höher können Sie die evaluateJavascriptMethode für die Webansicht verwenden

wvbrowser.evaluateJavascript(
        "(function() { return ('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>'); })();",
         new ValueCallback<String>() {
            @Override
            public void onReceiveValue(String html) {
                Log.d("HTML", html); 
                // code here
            }
    });

Weitere Beispiele finden Sie in dieser Antwort


Dies ist bei weitem die einfachste Lösung, um hier zu verwenden
Billy

9
Zu Ihrer Information - Benötigt API 19.
Joel

6
Denken Sie daran, dies in die onPageFinished-Methode einzufügen.
Cédric Portmann

@ Joel Wie erreicht man dies unter API 19?
Pratik Saluja

1
@PratikSaluja Es tut mir sehr leid, wenn mein Kommentar die falsche Idee vermittelt hat. Die Antwort mit den meisten positiven Stimmen hier ist viel älter als meine eigene Antwort und würde wahrscheinlich für Sie funktionieren. Bedeutete nichts weiter. Sehr froh, dass Sie die Antwort gefunden haben, indem Sie sich anderswo umgesehen haben.
Akash Kurian Jose

41

Vergessen Sie für Android 4.2 nicht, allen JavaScript-Funktionen @JavascriptInterface hinzuzufügen


1
Funktioniert für Android 4.2 und oben.
Cédric Portmann

10

Android WebView ist nur eine weitere Render-Engine, die HTML-Inhalte rendert, die von einem HTTP-Server heruntergeladen wurden, ähnlich wie Chrome oder FireFox. Ich weiß nicht, warum Sie die gerenderte Seite (oder den Screenshot) von WebView erhalten müssen. In den meisten Fällen ist dies nicht erforderlich. Sie können den HTML-Rohinhalt jederzeit direkt vom HTTP-Server abrufen.

Es gibt bereits Antworten zum Abrufen des Rohdatenstroms mithilfe von HttpUrlConnection oder HttpClient. Alternativ gibt es eine sehr praktische Bibliothek für das Parsen / Verarbeiten von HTML-Inhalten unter Android: JSoup . Sie bietet eine sehr einfache API zum Abrufen von HTML-Inhalten vom HTTP-Server und eine abstrakte Darstellung von HTML-Dokumenten, um nicht nur das Parsen von HTML zu verwalten in einem OO-Stil, aber auch sehr leicht:

// Single line of statement to get HTML document from HTTP server.
Document doc = Jsoup.connect("http://en.wikipedia.org/").get();

Dies ist praktisch, wenn Sie beispielsweise zuerst ein HTML-Dokument herunterladen und dann ein benutzerdefiniertes CSS oder Javascript hinzufügen möchten, bevor Sie es zum Rendern an WebView übergeben. Viel mehr auf ihrer offiziellen Website, es lohnt sich, es sich anzusehen.


5

Ein Berührungspunkt, den ich gefunden habe und der eingerichtet werden muss, ist in der Proguard-Konfiguration "versteckt". Während der HTML-Reader beim Debuggen der App problemlos über die Javascript-Oberfläche aufgerufen wird, funktioniert dies nicht mehr, sobald die App über Proguard ausgeführt wurde, es sei denn, die HTML-Reader-Funktion ist in der Proguard-Konfigurationsdatei wie folgt deklariert:

-keepclassmembers class <your.fully.qualified.HTML.reader.classname.here> {
    public *; 
}

Getestet und bestätigt auf Android 2.3.6, 4.1.1 und 4.2.1.


4

Android lässt Sie dies aus Sicherheitsgründen nicht tun. Ein böser Entwickler könnte sehr leicht vom Benutzer eingegebene Anmeldeinformationen stehlen.

Stattdessen müssen Sie den in der Webansicht angezeigten Text abfangen, bevor er angezeigt wird. Wenn Sie keinen Antwort-Handler einrichten möchten (wie in den anderen Antworten angegeben), habe ich diesen Fix mit einigem googeln gefunden:

URL url = new URL("/programming/1381617");
URLConnection con = url.openConnection();
Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*");
Matcher m = p.matcher(con.getContentType());
/* If Content-Type doesn't match this pre-conception, choose default and 
 * hope for the best. */
String charset = m.matches() ? m.group(1) : "ISO-8859-1";
Reader r = new InputStreamReader(con.getInputStream(), charset);
StringBuilder buf = new StringBuilder();
while (true) {
  int ch = r.read();
  if (ch < 0)
    break;
  buf.append((char) ch);
}
String str = buf.toString();

Dies ist eine Menge Code, und Sie sollten in der Lage sein, ihn zu kopieren / zu kopieren, und am Ende strwird er denselben HTML-Code enthalten, der in der Webansicht gezeichnet wurde. Diese Antwort ist auf einfachste Weise, um HTML von der Webseite korrekt in eine Zeichenfolge in Java zu laden, und sollte auch unter Android funktionieren. Ich habe dies nicht getestet und nicht selbst geschrieben, aber es könnte Ihnen helfen.

Außerdem ist die URL, die hier abgerufen wird, fest codiert, sodass Sie dies ändern müssen.


1

Warum nicht zuerst das HTML herunterladen und dann an die Webansicht übergeben?

private String getHtml(String url){
    HttpGet pageGet = new HttpGet(url);

    ResponseHandler<String> handler = new ResponseHandler<String>() {
        public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
            HttpEntity entity = response.getEntity();
            String html; 

            if (entity != null) {
                html = EntityUtils.toString(entity);
                return html;
            } else {
                return null;
            }
        }
    };

    pageHTML = null;
    try {
        while (pageHTML==null){
            pageHTML = client.execute(pageGet, handler);
        }
    } catch (ClientProtocolException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return pageHTML;
}

@Override
public void customizeWebView(final ServiceCommunicableActivity activity, final WebView webview, final SearchResult mRom) {
    mRom.setFileSize(getFileSize(mRom.getURLSuffix()));
    webview.getSettings().setJavaScriptEnabled(true);
    WebViewClient anchorWebViewClient = new WebViewClient()
    {

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);

            //Do what you want to with the html
            String html = getHTML(url);

            if( html!=null && !url.equals(lastLoadedURL)){
                lastLoadedURL = url;
                webview.loadDataWithBaseURL(url, html, null, "utf-8", url);
            }
}

Dies sollte ungefähr das tun, was Sie tun möchten. Es ist angepasst von Ist es möglich, den HTML-Code von WebView abzurufen und für seine Antwort an https://stackoverflow.com/users/325081/aymon-fournier zu senden .


HttpClient war in API Level 22 veraltet und wurde in API Level 23 entfernt. Daher können die in Ihrem Code genannten Klassen nicht in die Java-Dateien importiert werden.
Dhananjay M

1

Ich würde vorschlagen, anstatt zu versuchen, den HTML-Code aus der WebView zu extrahieren, den HTML-Code aus der URL zu extrahieren. Damit meine ich die Verwendung einer Drittanbieter-Bibliothek wie JSoup, um den HTML-Code für Sie zu durchlaufen. Der folgende Code ruft den HTML-Code von einer bestimmten URL für Sie ab

public static String getHtml(String url) throws ClientProtocolException, IOException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpContext localContext = new BasicHttpContext();
        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = httpClient.execute(httpGet, localContext);
        String result = "";

        BufferedReader reader = new BufferedReader(
            new InputStreamReader(
                response.getEntity().getContent()
            )
        );

        String line = null;
        while ((line = reader.readLine()) != null){
            result += line + "\n";
        }
        return result;
    }

Angenommen, die erhaltene URL wird durch das Posten von Daten erreicht. Diese Methode schlägt fehl.
Jafar Ali

Und was ist mit Cookies?
Keith Adler

0

Es ist einfach zu implementieren. Sie benötigen lediglich Javasript-Methoden in Ihrem HTML-Code, um den Wert des HTML-Inhalts zu ermitteln. Wie über Ihrem Code müssen einige Änderungen vorgenommen werden.

  public class htmldecoder extends Activity implements OnClickListener,TextWatcher
    {
    Button btsubmit; // this button in your xml file
    WebView wvbrowser;
    public void onCreate(Bundle savedInstanceState)
    {
                super.onCreate(savedInstanceState);
                    setContentView(R.layout.htmldecoder);



        btsubmit=(Button)findViewById(R.id.btsubmit);
        btsubmit.setOnClickListener(this);

        wvbrowser=(WebView)findViewById(R.id.wvbrowser);
        wvbrowser.setWebViewClient(new HelloWebViewClient());
        wvbrowser.getSettings().setJavaScriptEnabled(true);
        wvbrowser.getSettings().setPluginsEnabled(true);
        wvbrowser.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        MyJavaScriptInterface myinterface=new MyJavaScriptInterface();
        wvbrowser.addJavascriptInterface(myinterface,"interface");
        webView.loadUrl("file:///android_asset/simple.html");  //use one html file for //testing put your html file in assets. Make sure that you done JavaScript methods to get //values for html content in html file . 
   }
   public void onClick(View v)
{
    if(btsubmit==v)
    {

        webView.loadUrl("javascript:showalert()");// call javascript method.  
        //wvbr
    }
}

final class MyJavaScriptInterface {



        MyJavaScriptInterface() {

        }

        public void sendValueFromHtml(String value) {
           System.out.println("Here is the value from html::"+value);
        }

    }

}

Ihr Javascript in HTML

 <script type="text/javascript">
    //<![CDATA[
    var n1;
    function callme(){
    n1=document.getElementById("FacadeAL").value;
    }
    function showalert(){
     window.interface.sendValueFromHtml(n1);// this method calling the method of interface which //you attached to html file in android. // & we called this showalert javasript method on //submmit buttton click of android. 
    }
    //]]>
    </script>

& Stellen Sie sicher, dass Sie callme wie unten in HTML aufrufen

<input name="FacadeAL" id="FacadeAL" type="text" size="5" onblur="callme()"/>
Hoffe das wird dir helfen.


Was bedeutet das & Make sure you calling callme like below in html? Wollten Sie das Eingabe-Tag in der HTML-Datei unter dem Skript platzieren? Thank You

Kein Typ, Sie müssen die Javasript-Methode callme () aufrufen, um den Text vom Eingabetyp im HTML-Tag zu verwischen.
Herr Sajid Shaikh

Wo kann man dann dieses Eingabe-Tag hinzufügen? Ist diese Schaltfläche sichtbar?

Dieser Code funktioniert wie beim Laden von Aktivitäten gibt es ein Textfeld in der Webansicht und der eingegebene Text wird im Textfeld angezeigt. Aber ich möchte den HTML-Code in der Webansicht.

Kannst du mir helfen, dieses Problem zu lösen? Thank you very much

0

Ich schlage vor, einen Reflection-Ansatz auszuprobieren, wenn Sie Zeit für den Debugger haben (sorry, aber ich hatte keine).

Ausgehend von der loadUrl()Methode der android.webkit.WebViewKlasse:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/webkit/WebView.java#WebView.loadUrl%28java.lang.String % 2Cjava.util.Map% 29

Sie sollten auf dem android.webkit.BrowserFramelanden, der die nativeLoadUrl()native Methode aufruft:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/webkit/BrowserFrame.java#BrowserFrame.nativeLoadUrl%28java.lang.String % 2Cjava.util.Map% 29

Die Implementierung der nativen Methode sollte hier sein:

http://gitorious.org/0xdroid/external_webkit/blobs/a538f34148bb04aa6ccfbb89dfd5fd784a4208b1/WebKit/android/jni/WebCoreFrameBridge.cpp

Wünsche dir viel Glück!


-1

Versuchen Sie, HttpClient zu verwenden, wie Sephy sagte:

public String getHtml(String url) {
    HttpClient vClient = new DefaultHttpClient();
    HttpGet vGet = new HttpGet(url);
    String response = "";    

    try {
        ResponseHandler<String> vHandler = new BasicResponseHandler();
        response = vClient.execute(vGet, vHandler);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return response;
}

Können Sie ein einfaches Arbeitsbeispiel zeigen?
Ich

Diese Methode erhält die HTML-Quelle der angegebenen URL. dh getHtml ( google.com ); erhalten Sie die Quelle der Google-Hauptseite
Christoper Hans

Es ist in Ordnung. Gibt es eine Option, um eine Webview-Quelle zu erhalten? THANKS
KIRAN KJ

Das hat bei mir etwas nicht funktioniert. Ich habe keinen Inhalt von einer Testseite erhalten, deren Inhalt "Hallo Welt" war.
Momro

-2

Die oben angegebenen Methoden sind für, wenn Sie eine Web-URL haben, aber wenn Sie eine lokale HTML haben, können Sie auch HTML durch diesen Code haben

AssetManager mgr = mContext.getAssets();
             try {
InputStream in = null;              
if(condition)//you have a local html saved in assets
                            {
                            in = mgr.open(mFileName,AssetManager.ACCESS_BUFFER);
                           }
                            else if(condition)//you have an url
                            {
                            URL feedURL = new URL(sURL);
                  in = feedURL.openConnection().getInputStream();}

                            // here you will get your html
                 String sHTML = streamToString(in);
                 in.close();

                 //display this html in the browser or web view              


             } catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
             }
        public static String streamToString(InputStream in) throws IOException {
            if(in == null) {
                return "";
            }

            Writer writer = new StringWriter();
            char[] buffer = new char[1024];

            try {
                Reader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));

                int n;
                while ((n = reader.read(buffer)) != -1) {
                    writer.write(buffer, 0, n);
                }

            } finally {

            }

            return writer.toString();
        }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.