วิธีรับเนื้อหา html จาก webview


123

วิธีใดเป็นวิธีที่ง่ายที่สุดในการรับโค้ด html จาก webview ฉันลองหลายวิธีจาก stackoverflow และ google แล้ว แต่ไม่พบวิธีที่แน่นอน โปรดระบุวิธีที่แน่นอน

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

}

}

คำตอบ:


107

จริงๆแล้วคำถามนี้มีหลายคำตอบ นี่คือ 2 รายการ:

  • ครั้งแรกนี้เกือบจะเหมือนกับของคุณฉันเดาว่าเราได้มาจากบทช่วยสอนเดียวกัน

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

    }
}

วิธีนี้ของคุณคว้า html ผ่านจาวาสคริปต์ ไม่ใช่วิธีที่สวยที่สุด แต่เมื่อคุณมีอินเทอร์เฟซจาวาสคริปต์คุณสามารถเพิ่มวิธีการอื่น ๆ เพื่อคนจรจัดได้


  • วิธีการอื่น ๆ โดยใช้ HttpClient เหมือนมี

ตัวเลือกที่คุณเลือกก็ขึ้นอยู่กับสิ่งที่คุณตั้งใจจะทำกับ html ที่ดึงมา ...


เมื่อดำเนินการตามบรรทัดนี้webview.loadUrl("javascript:window.HtmlViewer.showHTML" + "('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");โปรแกรมจะทำหน้าที่เหมือนฟังก์ชันเสร็จสิ้น () และหยุดกิจกรรมนั้นทำไมจะแก้อย่างไร

7
webview.addJavascriptInterface ใช้ได้กับ Jelly Beans และเวอร์ชันที่ต่ำกว่าเท่านั้น
xtr

32
การเปลี่ยนแปลงที่สำคัญสองประการในโค้ดด้านบนสำหรับ Jellybean และใหม่กว่า: 1. ลบ "หน้าต่าง" จากบรรทัด webview.loadUrl - อินเทอร์เฟซ javascript ถูกแนบแตกต่างกันเมื่อกำหนดเป้าหมาย Jellybean 2. ใส่ @JavascriptInterface ก่อน "public void showHTML" - สิ่งนี้จำเป็นเนื่องจากเป็นความเสี่ยงด้านความปลอดภัยที่ไม่เพียง แต่อนุญาตให้เรียกวิธีการบางอย่างเท่านั้น
karlbecker_com

1
ยังใช้ไม่ได้สำหรับฉัน (5.1.1) .. เมื่อฉันเพิ่ม MyJavaScriptInterface (พร้อมคำใบ้ @karlbecker_com) เมื่อฉันคลิกบางสิ่งในระบบหน้าที่โหลดขอให้ฉันเลือกเบราว์เซอร์ เมื่อฉันลบสิ่งนี้มันจะไม่ถามฉันอีก
Makalele

1
ที่นี่ฉันเปิดใช้งานการดีบักระยะไกลมันแสดงให้เห็นUncaught ReferenceError: HtmlViewer is not definedไม่ว่าจะมีหรือไม่มี@JavascriptInterface
ก็ตาม

55

ใน KitKat ขึ้นไปคุณสามารถใช้evaluateJavascriptวิธีการบน webview

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

ดูคำตอบนี้สำหรับตัวอย่างเพิ่มเติม


นี่เป็นวิธีที่ง่ายที่สุดที่จะใช้ที่นี่
Billy

9
FYI - ต้องใช้ API 19
Joel

7
อย่าลืมใส่สิ่งนี้ลงในเมธอด onPageFinished
Cédric Portmann

@Joel จะบรรลุสิ่งนี้ด้านล่าง API 19 ได้อย่างไร
Pratik Saluja

1
@PratikSaluja ขออภัยเป็นอย่างยิ่งหากความคิดเห็นของฉันสื่อถึงความคิดที่ผิด คำตอบที่มีการโหวตมากที่สุดที่นี่เก่ากว่าคำตอบของฉันมากและน่าจะเหมาะกับคุณ ไม่ได้มีความหมายอะไรนอกเหนือไปจากนั้น ดีใจมากที่คุณพบคำตอบโดยดูที่อื่น BTW
Akash Kurian Jose

41

สำหรับ Android 4.2 อย่าลืมเพิ่ม @JavascriptInterface ให้กับฟังก์ชั่น javasscript ทั้งหมด


1
ใช้งานได้กับ Android 4.2 และ ABOVE
Cédric Portmann

10

Android WebView เป็นเพียงเครื่องมือแสดงผลอีกตัวที่แสดงเนื้อหา HTML ที่ดาวน์โหลดจากเซิร์ฟเวอร์ HTTP เช่นเดียวกับ Chrome หรือ FireFox ฉันไม่รู้เหตุผลว่าทำไมคุณต้องรับหน้าที่แสดงผล (หรือภาพหน้าจอ) จาก WebView ไม่จำเป็นสำหรับสถานการณ์ส่วนใหญ่ คุณสามารถรับเนื้อหา HTML ดิบจากเซิร์ฟเวอร์ HTTP ได้โดยตรง

มีคำตอบที่โพสต์ไว้แล้วเกี่ยวกับการรับสตรีมดิบโดยใช้ HttpUrlConnection หรือ HttpClient อีกวิธีหนึ่งคือมีไลบรารีที่สะดวกมากเมื่อจัดการกับการแยกวิเคราะห์เนื้อหา HTML / กระบวนการบน Android: JSoupซึ่งมี API ที่ง่ายมากในการรับเนื้อหา HTML จากเซิร์ฟเวอร์ HTTP และจัดเตรียมเอกสาร HTML ที่เป็นนามธรรมเพื่อช่วยในการจัดการการแยกวิเคราะห์ HTML ไม่เพียง ในรูปแบบ OO มากขึ้น แต่ยังง่ายมาก:

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

มีประโยชน์มากเมื่อคุณต้องการดาวน์โหลดเอกสาร HTML ก่อนจากนั้นเพิ่ม css หรือ javascript ที่กำหนดเองก่อนที่จะส่งไปยัง WebView เพื่อแสดงผล อีกมากมายในเว็บไซต์อย่างเป็นทางการของพวกเขาคุ้มค่าที่จะตรวจสอบ


5

จุดสัมผัสหนึ่งที่ฉันพบว่าต้องถูก "ซ่อน" ไว้ในการกำหนดค่า Proguard ในขณะที่โปรแกรมอ่าน HTML เรียกใช้ผ่านอินเทอร์เฟซจาวาสคริปต์ได้ดีเมื่อทำการดีบักแอป แต่จะไม่ทำงานอีกต่อไปทันทีที่แอปทำงานผ่าน Proguard เว้นแต่จะมีการประกาศฟังก์ชันการอ่าน HTML ในไฟล์กำหนดค่า Proguard ดังนี้:

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

ทดสอบและยืนยันบน Android 2.3.6, 4.1.1 และ 4.2.1


4

Android จะไม่ยอมให้คุณทำเช่นนี้เนื่องจากปัญหาด้านความปลอดภัย นักพัฒนาที่ชั่วร้ายสามารถขโมยข้อมูลล็อกอินที่ผู้ใช้ป้อนได้อย่างง่ายดาย

แต่คุณต้องจับข้อความที่แสดงใน webview ก่อนจึงจะแสดงได้ หากคุณไม่ต้องการตั้งค่าตัวจัดการการตอบกลับ (ตามคำตอบอื่น ๆ ) ฉันพบการแก้ไขนี้กับ googling:

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

นี่เป็นโค้ดจำนวนมากและคุณควรจะสามารถคัดลอก / วางโค้ดได้และในตอนท้ายของstrโค้ดนั้นจะมี html เดียวกับที่วาดใน webview คำตอบนี้มาจากวิธีที่ง่ายที่สุดในการโหลด html จากหน้าเว็บเป็นสตริงใน Java อย่างถูกต้องและควรทำงานบน Android ด้วย ฉันยังไม่ได้ทดสอบและไม่ได้เขียนเอง แต่อาจช่วยคุณได้

นอกจากนี้ URL ที่ดึงออกมานั้นเป็นแบบฮาร์ดโค้ดดังนั้นคุณจะต้องเปลี่ยน


1

ทำไมไม่รับ html ก่อนแล้วส่งไปยังมุมมองเว็บ

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

ประมาณนี้ควรทำในสิ่งที่คุณต้องการทำ มันดัดแปลงมาจากเป็นไปได้หรือไม่ที่จะรับโค้ด HTML จาก WebView และตะโกนไปที่https://stackoverflow.com/users/325081/aymon-fournierเพื่อรับคำตอบ


HttpClient เลิกใช้งานแล้วใน API ระดับ 22 และถูกลบออกใน API ระดับ 23 ดังนั้นคลาสที่กล่าวถึงในโค้ดของคุณจึงไม่สามารถนำเข้าในไฟล์ java ได้
Dhananjay M

1

ฉันขอแนะนำแทนที่จะพยายามแยก HTML จาก WebView คุณแยก HTML ออกจาก URL ด้วยเหตุนี้ฉันหมายถึงการใช้ไลบรารีของบุคคลที่สามเช่น JSoup เพื่อสำรวจ HTML ให้คุณ โค้ดต่อไปนี้จะได้รับ HTML จาก URL เฉพาะสำหรับคุณ

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

สมมติว่าได้รับ url โดยการโพสต์ข้อมูล วิธีนี้จะล้มเหลว
Jafar Ali

แล้วคุกกี้ล่ะ?
Keith Adler

0

ใช้งานง่ายเพียงแค่ต้องใช้วิธีการ javasript ใน html ของคุณเพื่อรับคุณค่าของเนื้อหา html ข้างบนโค้ดของคุณจำเป็นต้องมีการเปลี่ยนแปลงบางอย่าง

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

    }

}

Javascript ของคุณในรูปแบบ 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>

& ตรวจสอบให้แน่ใจว่าคุณเรียก callme ตามที่ระบุไว้ด้านล่างใน html

<input name="FacadeAL" id="FacadeAL" type="text" size="5" onblur="callme()"/>
หวังว่านี่จะช่วยคุณได้


หมายความว่า& Make sure you calling callme like below in htmlอย่างไรคุณหมายถึงการวางแท็กอินพุตไว้ด้านล่างสคริปต์ในไฟล์ html หรือไม่? Thank You

ไม่มีเพื่อนคุณต้องเรียกเมธอด javasript callme () onblur ของข้อความประเภทอินพุตในแท็ก html
Mr.Sajid Shaikh

แล้วจะเพิ่มแท็กอินพุตนี้ได้ที่ไหนปุ่มนี้มองเห็นได้หรือไม่

รหัสนี้ใช้งานได้เมื่อโหลดกิจกรรมจะมีกล่องข้อความใน webview และข้อความที่พิมพ์จะแสดงที่กล่องข้อความ แต่ฉันต้องการรหัส html ใน webview

คุณช่วยฉันแก้ปัญหานี้ได้ไหม Thank you very much

0

ฉันขอแนะนำให้ลองใช้วิธีการสะท้อนกลับหากคุณมีเวลาใช้กับดีบักเกอร์ (ขออภัยฉันไม่มี)

เริ่มต้นจากloadUrl()วิธีการของandroid.webkit.WebViewคลาส:

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%

คุณควรมาถึงandroid.webkit.BrowserFrameที่เรียกว่าnativeLoadUrl()วิธีดั้งเดิม:

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%

การใช้งานวิธีดั้งเดิมควรอยู่ที่นี่:

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

ขอให้คุณโชคดี!


-1

ลองใช้ HttpClient ตามที่ Sephy กล่าวไว้:

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

คุณช่วยแสดงตัวอย่างการทำงานง่ายๆได้ไหมฉันไม่สามารถใช้โค้ดของคุณในตัวอย่างของ sephy ได้
KIRAN KJ

วิธีนี้จะได้แหล่งที่มา html ของ url ที่กำหนด คือ getHtml ( google.com ); จะทำให้คุณได้รับแหล่งที่มาของหน้าหลักของ Google
Christoper Hans

มันโอเคมีตัวเลือกใดบ้างในการรับแหล่งที่มาของการดูเว็บ THANKS
KIRAN KJ

สิ่งนี้ค่อนข้างไม่ได้ผลสำหรับฉัน ฉันไม่ได้รับเนื้อหาใด ๆ จากไซต์ทดสอบที่มีเนื้อหา "สวัสดีชาวโลก"
Momro

-2

วิธีการที่ระบุข้างต้นมีไว้สำหรับถ้าคุณมี URL ของเว็บ แต่ถ้าคุณมี html ในเครื่องคุณสามารถมี html ได้ด้วยรหัสนี้

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();
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.