天天看點

Java擷取網頁編碼

    使用爬蟲從網上抓取到一個網頁内容,要想能正确顯示,必須要擷取網頁的原始編碼,否則會出現亂碼。首先需要擷取網頁内容,最簡單的辦法就是通過jdk自帶的httpurlconnection類,要實作更複雜的抓取操作,請使用開源的爬蟲架構,如crawler4j,web-harvest,jspider,webmagic,heritrix,nutch等,我并不是來說爬蟲相關技術的,隻是網頁内容的擷取需要使用到爬蟲技術,是以順帶提提有關爬蟲的架構,具體你們自己去研究。這裡為了簡便起見,我就以jdk自帶的httpurlconnection類來抓取網頁内容,抓取示例代碼如下:

Java擷取網頁編碼

package com.yida.test;  

import java.io.bufferedreader;  

import java.io.ioexception;  

import java.io.inputstreamreader;  

import java.net.httpurlconnection;  

import java.net.url;  

/** 

 * 提取網頁内容 

 * @author lanxiaowei 

 * 

 */  

public class fetchwebpagetest {  

    public static void main(string[] args) throws ioexception {  

        string charset = "utf-8";  

        string line = "";  

        stringbuffer buffer = new stringbuffer();  

        url url = new url("http://www.baidu.com");  

        //開始通路該url  

        httpurlconnection urlconnection = (httpurlconnection)url.openconnection();  

        //擷取伺服器響應代碼  

        int responsecode = urlconnection.getresponsecode();  

        string contenttype = urlconnection.getcontenttype();  

        //列印出content-type值,然後就可以從content-type中提取出網頁編碼  

        system.out.println("content-type:" + contenttype);  

        if(responsecode == 200){  

            //擷取網頁輸入流  

            bufferedreader reader = new bufferedreader(new inputstreamreader(urlconnection.getinputstream(),charset));  

            while((line = reader.readline()) != null){  

                buffer.append(line).append("\n");  

            }  

            system.out.println(buffer.tostring());  

        }  

        else{  

            system.out.println("擷取不到網頁的源碼,伺服器響應代碼為:"+responsecode);  

        urlconnection.disconnect();  

    }  

}  

     關鍵點在這一句代碼:

Java擷取網頁編碼

bufferedreader reader = new bufferedreader(new inputstreamreader(urlconnection.getinputstream(),charset));  

   這裡的charset表示網頁内容的字元集編碼,上面的示例代碼中charset是直接定義為utf-8,實際我們期望是能自動判斷,因為并不是所有網頁内容的字元集編碼都為utf-8,這也是我們今天這篇文章的主題:如何擷取網頁内容的原始字元集編碼。

    首先,我們可以通過urlconnection類的getcontenttype()方法的傳回值中擷取,比如:

Java擷取網頁編碼

string contenttype = urlconnection.getcontenttype();  

     傳回值類似這樣:

Java擷取網頁編碼

content-type:text/html; charset=utf-8  

     然後我們從字元串中提取出字元集編碼,剩下這就是字元串處理了,沒什麼難度,你們都懂的!

    當然,urlconnection類的getcontenttype()方法的傳回值并不能保證一定會包含字元集編碼,這時我們就需要另辟蹊徑,我們都知道一般html頁面源代碼中都會包含<meta标簽,如:

Java擷取網頁編碼

<%@ page language="java" contenttype="text/html; charset=utf-8"  

    pageencoding="utf-8"%>  

<!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/html4/loose.dtd">  

<html>  

<head>  

<meta http-equiv="content-type" content="text/html; charset=utf-8">  

<title>歡迎頁面</title>  

</head>  

<body>  

歡迎頁面  

</body>  

</html>    

     關鍵點在這裡:

Java擷取網頁編碼

     我們可以通過正規表達式從中提取出編碼,示例代碼如下:

Java擷取網頁編碼

import java.util.regex.matcher;  

import java.util.regex.pattern;  

 * 從html網頁的meta元素中提取頁面編碼 

 * 這裡采用的是正規表達式方式提取,你也可以采用xml解析的方式來提取[html其實就是xml] 

public class charsetextracttest {  

    public static void main(string[] args) {  

        //test1();  

        test2();  

    /** 

     * 正常情況 

     */  

    public static void test1() {  

        string content="<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +  

                "<head>\n" +  

                "<meta http-equiv = \"content-type\" content = \"text/html; charset=utf-8\" />\n" +  

                "<meta content=\"java擷取 html網頁編碼\" name=\"keywords\"/>...\n";  

        pattern pattern = pattern.compile("<meta\\s+http-equiv\\s*=\\s*\"content-type\"\\s+content\\s*=\\s*\"[\\s\\s]*?charset=(\\s+?)\"\\s*/>");  

        matcher matcher=pattern.matcher(content);  

        if(matcher.find()){  

            system.out.println(matcher.group(1));  

     * 非正常情況,比如http-equiv和content屬性颠倒了 

    public static void test2() {  

                "<meta content = \"text/html; charset=utf-8\" http-equiv = \"content-type\" />\n" +  

        string regex = "(<meta\\s+http-equiv\\s*=\\s*\"content-type\"\\s+content\\s*=\\s*\"[\\s\\s]*?charset=(\\s+?)\"\\s*/>)|" +   

                "(<meta\\s+content\\s*=\\s*\"[\\s\\s]*?charset=(\\s+?)\"\\s+http-equiv\\s*=\\s*\"content-type\"\\s*/>)";  

        pattern pattern = pattern.compile(regex);  

            system.out.println(matcher.group(4));  

     但遺憾的是,并不是每個網頁内容都包含meta标簽,因為總有些人不遵守html規範,這是我們該怎麼辦?還好我們還有一招可以來應對這種情形,那就是ibm的icu4j類庫,icu4j可以從指定的位元組資料從自動推斷出其采用的字元集編碼,具體示例代碼如下:

Java擷取網頁編碼

import java.io.inputstream;  

import com.ibm.icu.text.charsetdetector;  

import com.ibm.icu.text.charsetmatch;  

 * 使用icu4j探測内容編碼,這裡的内容可以來自于字元串,位元組數組,輸入流等等 

 *  

public class icu4jtest {  

        string data = "icu4j 是ibm的國際化開發元件icu的java語言實作版本。";  

        string encode = getencode(data);  

        system.out.println("encode:" + encode);  

    public static string getencode(string data) {  

        return getencode(data.getbytes());  

    public static string getencode(byte[] data) {  

        charsetdetector detector = new charsetdetector();  

        detector.settext(data);  

        charsetmatch match = detector.detect();  

        //取confidence值最大的  

        string encoding = match.getname();  

        system.out.println("the content in " + match.getname());  

        charsetmatch[] matches = detector.detectall();  

        system.out.println("all possibilities");  

        for (charsetmatch m : matches) {  

            system.out.println("charsetname:" + m.getname() + " confidence:"  

                    + m.getconfidence());  

        return encoding;  

    public static string getencode(inputstream data)  

            throws ioexception {  

     還有一點需要注意的就是,如果抓取到的網頁内容輸入流不管是使用gbk還是utf-8,都全是亂碼,那很有可能是該網頁所在伺服器對其采用gzip壓縮,是以在擷取到網頁輸入流時首先需要對其進行gzip解壓縮,那如何确定對方伺服器是否有對網頁進行gzip壓縮呢,一般可以通過響應頭資訊中擷取到,如果響應頭裡包含了如下資訊:

Java擷取網頁編碼

accept-encoding: gzip,deflate    

     則表明該網頁被gzip壓縮過,在擷取網頁内容之前,需要一個gzip解壓縮過程,特此提醒!gzip解壓縮示例代碼如下:

Java擷取網頁編碼

inputstream is = urlconnection.getinputstream();  

//用gzipinputstream 對原始的輸入流包裝一下  

gzipinputstream gis = new gzipinputstream(he.getcontent());  

bufferedreader reader = new bufferedreader(new inputstreamreader(gis,charset));  

   上述所有示例代碼打包上傳到我的百度網盤,代碼下載下傳位址如下:

    http://pan.baidu.com/s/1ktgqi0z

    如果你還有什麼問題請加我Q-q:7-3-6-0-3-1-3-0-5,

或者加裙

Java擷取網頁編碼

一起交流學習!

轉載:http://iamyida.iteye.com/blog/2206228