¿Cómo obtener contenido html de una vista web?

123

¿Cuál es el método más simple para obtener código html de una vista web? He probado varios métodos de stackoverflow y google, pero no puedo encontrar un método exacto. Por favor mencione una manera exacta.

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

}

}
Hope4You
fuente

Respuestas:

107

En realidad esta pregunta tiene muchas respuestas. Aquí hay 2 de ellos:

  • Esto primero es casi lo mismo que el tuyo, supongo que lo obtuvimos del mismo tutorial.

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

    }
}

De esta manera, puedes tomar el HTML a través de JavaScript. No es la forma más bonita, pero cuando tiene su interfaz de JavaScript, puede agregar otros métodos para modificarla.


  • Otra forma es usar un HttpClient como allí .

La opción que elija también depende, creo, de lo que piensa hacer con el html recuperado ...

Sephy
fuente
cuando ejecuta esta línea, webview.loadUrl("javascript:window.HtmlViewer.showHTML" + "('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");el programa actúa como la función terminar () y detiene esa actividad. ¿Por qué? ¿Cómo resolverlo?
77
webview.addJavascriptInterface solo funciona en Jelly Beans y versiones inferiores.
xtr
32
Dos cambios importantes en el código anterior para Jellybean y posteriores: 1. Elimine "window". desde la línea webview.loadUrl: la interfaz de JavaScript se conecta de manera diferente cuando se dirige a Jellybean. 2. Ponga @JavascriptInterface antes de "public void showHTML": esto es necesario ya que es un riesgo de seguridad no solo permitir que se invoquen ciertos métodos.
karlbecker_com
1
Todavía no funciona para mí (5.1.1). Cuando agrego MyJavaScriptInterface (con @karlbecker_com pistas) cuando hago clic en algo en el sistema de página cargado, me pide que elija el navegador. Cuando elimine esto, no me volverá a preguntar.
Makalele
1
Aquí habilité la depuración remota, mostró Uncaught ReferenceError: HtmlViewer is not defined, sin importar con o sin@JavascriptInterface
MewX
55

En KitKat y evaluateJavascriptversiones posteriores, puede usar el método en la vista web

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

Vea esta respuesta para más ejemplos.

Akash Kurian Jose
fuente
Esta es, con mucho, la solución más fácil de usar aquí
Billy
9
FYI - Requiere API 19.
Joel
77
Recuerde poner esto en el método onPageFinished.
Cédric Portmann el
@Joel ¿Cómo lograr esto debajo de API 19?
Pratik Saluja
1
@PratikSaluja lo siento mucho si mi comentario transmitió la idea equivocada. La respuesta con la mayoría de los votos a favor aquí es mucho más antigua que mi propia respuesta y probablemente funcione para usted. No significaba nada más que eso. Muy contento de haber encontrado la respuesta al buscar en otro lado BTW.
Akash Kurian José
41

Para Android 4.2, no olvide agregar @JavascriptInterface a todas las funciones de javasscript

usuario1842354
fuente
1
Funciona para Android 4.2 y ARRIBA.
Cédric Portmann
10

Android WebView es solo otro motor de renderizado que renderiza contenido HTML descargado de un servidor HTTP, al igual que Chrome o Firefox. No sé la razón por la que necesita obtener la página renderizada (o captura de pantalla) de WebView. Para la mayoría de las situaciones, esto no es necesario. Siempre puede obtener el contenido HTML sin procesar del servidor HTTP directamente.

Ya hay respuestas publicadas que hablan sobre cómo obtener la transmisión sin formato utilizando HttpUrlConnection o HttpClient. Alternativamente, hay una biblioteca muy útil cuando se trata de análisis / proceso de contenido HTML en Android: JSoup , proporciona una API muy simple para obtener contenido HTML del servidor HTTP, y proporciona una representación abstracta del documento HTML para ayudarnos a administrar el análisis HTML. en un estilo más OO pero también mucho más fácil:

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

Es útil cuando, por ejemplo, desea descargar un documento HTML primero y luego agregar un CSS o JavaScript personalizado antes de pasarlo a WebView para su representación. Mucho más en su sitio web oficial, vale la pena echarle un vistazo.

yorkw
fuente
5

Un punto de contacto que encontré que debe ponerse en su lugar está "oculto" en la configuración de Proguard. Si bien el lector HTML invoca a través de la interfaz de JavaScript muy bien al depurar la aplicación, esto ya no funciona tan pronto como la aplicación se ejecutó a través de Proguard, a menos que la función del lector HTML se declare en el archivo de configuración de Proguard, así:

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

Probado y confirmado en Android 2.3.6, 4.1.1 y 4.2.1.

usuario1756541
fuente
4

Android no te permitirá hacer esto por cuestiones de seguridad. Un desarrollador malvado podría robar fácilmente la información de inicio de sesión ingresada por el usuario.

En su lugar, debe captar el texto que se muestra en la vista web antes de que se muestre. Si no desea configurar un controlador de respuestas (según las otras respuestas), encontré esta solución con algunas búsquedas en Google:

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

Esto es mucho código, y debería poder copiarlo / pegarlo, y al final strcontendrá el mismo html dibujado en la vista web. Esta respuesta es de la manera más simple de cargar correctamente html desde la página web en una cadena en Java y también debería funcionar en Android. No he probado esto y no lo escribí yo mismo, pero podría ayudarte.

Además, la URL que está extrayendo está codificada, por lo que tendrá que cambiar eso.

edthethird
fuente
1

¿Por qué no obtener el html primero y luego pasarlo a la vista web?

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

Esto debería hacer aproximadamente lo que quieres hacer. Está adaptado de ¿Es posible obtener el código HTML de WebView y gritar a https://stackoverflow.com/users/325081/aymon-fournier por su respuesta.

Karl L
fuente
HttpClient fue desaprobado en API Nivel 22 y eliminado en API Nivel 23. Por lo tanto, las clases mencionadas en su código no pueden importarse en los archivos java.
Dhananjay M
1

Sugeriría que, en lugar de intentar extraer el HTML de WebView, extraiga el HTML de la URL. Con esto, me refiero a usar una biblioteca de terceros como JSoup para atravesar el HTML por usted. El siguiente código obtendrá el HTML de una URL específica para usted

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;
    }
Mimminito
fuente
supongamos que se alcanza la URL obtenida mediante la publicación de datos. Este método fallará.
Jafar Ali
¿Y qué hay de las cookies?
Keith Adler
0

Es fácil de implementar. Solo necesita métodos javasript en su html para obtener el valor del contenido html. Como arriba de su código, se necesitarán algunos cambios.

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

    }

}

Tu Javascript en 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>

& Asegúrese de llamar callme como se muestra a continuación en html

<input name="FacadeAL" id="FacadeAL" type="text" size="5" onblur="callme()"/>
Espero que esto te ayudará.

Sr. Sajid Shaikh
fuente
¿Qué significa esto & Make sure you calling callme like below in html? ¿Querías colocar la etiqueta de entrada debajo del script en el archivo html? Thank You
no dude, debe llamar al método javasript callme () onblur del texto de tipo de entrada en la etiqueta html.
Sr. Sajid Shaikh
entonces, ¿dónde agregar esta etiqueta de entrada? ¿Este botón está visible?
este código funciona como, cuando se carga la actividad, hay un cuadro de texto en la vista web y el texto escrito se muestra en el cuadro de texto, pero quiero el código html en la vista web.
¿Me pueden ayudar a resolver este problema? Thank you very much
0

Sugiero probar algún enfoque de Reflexión, si tiene tiempo para gastar en el depurador (lo siento, pero no lo hice).

A partir del loadUrl()método de laandroid.webkit.WebView clase:

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

Deberías llegar a android.webkit.BrowserFrameesa llamadanativeLoadUrl() método nativo:

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

La implementación del método nativo debería estar aquí:

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

¡Te deseo buena suerte!

Lechuckcaptain
fuente
-1

intente usar HttpClient como Sephy dijo:

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;
}
Christoper Hans
fuente
puede mostrar un ejemplo de trabajo simple. No puedo implementar su código en el ejemplo de Sephy
KIRAN KJ
este método obtendrá la fuente html de la url dada. es decir, getHtml ( google.com ); le proporcionará la fuente de la página principal de Google
Christoper Hans
está bien. hay alguna opción para obtener la fuente webview. THANKS
KIRAN KJ
Esto de alguna manera no funcionó para mí. No obtuve ningún contenido de un sitio de prueba cuyo contenido había sido "hola mundo".
Momro
-2

los métodos dados anteriormente son para si tiene una URL web, pero si tiene un html local, entonces también puede tener html por este código

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();
        }
vipin
fuente