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

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();
}
}
關鍵點在這一句代碼:

bufferedreader reader = new bufferedreader(new inputstreamreader(urlconnection.getinputstream(),charset));
這裡的charset表示網頁内容的字元集編碼,上面的示例代碼中charset是直接定義為utf-8,實際我們期望是能自動判斷,因為并不是所有網頁内容的字元集編碼都為utf-8,這也是我們今天這篇文章的主題:如何擷取網頁内容的原始字元集編碼。
首先,我們可以通過urlconnection類的getcontenttype()方法的傳回值中擷取,比如:

string contenttype = urlconnection.getcontenttype();
傳回值類似這樣:

content-type:text/html; charset=utf-8
然後我們從字元串中提取出字元集編碼,剩下這就是字元串處理了,沒什麼難度,你們都懂的!
當然,urlconnection類的getcontenttype()方法的傳回值并不能保證一定會包含字元集編碼,這時我們就需要另辟蹊徑,我們都知道一般html頁面源代碼中都會包含<meta标簽,如:

<%@ 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>
關鍵點在這裡:

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

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可以從指定的位元組資料從自動推斷出其采用的字元集編碼,具體示例代碼如下:

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壓縮呢,一般可以通過響應頭資訊中擷取到,如果響應頭裡包含了如下資訊:

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

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,
或者加裙
一起交流學習!
轉載:http://iamyida.iteye.com/blog/2206228