java判斷網頁的編碼格式,java判斷編碼格式
在爬取內容時,遇到亂碼問題。故需對網頁內容編碼格式做判斷,方式大體分為三種:一、從header標籤中擷取Content-Type=#Charset;二、從meta標籤中擷取Content-Type=#Charset;三、根據頁面內容分析編碼格式。
其中一/二方式並不能準確指示該頁面的具體編碼方式,周全考慮,加入第三種方式。
第三種方式引入開源jar包info.monitorenter.cpdetector,可以從github上面下載(https://github.com/onilton/cpdetector-maven-repo/tree/master/info/monitorenter/cpdetector/1.0.10)下載。整個代碼如下:
1 import info.monitorenter.cpdetector.io.ASCIIDetector; 2 import info.monitorenter.cpdetector.io.ByteOrderMarkDetector; 3 import info.monitorenter.cpdetector.io.CodepageDetectorProxy; 4 import info.monitorenter.cpdetector.io.JChardetFacade; 5 import info.monitorenter.cpdetector.io.ParsingDetector; 6 import info.monitorenter.cpdetector.io.UnicodeDetector; 7 8 import java.io.ByteArrayInputStream; 9 import java.io.IOException; 10 import java.io.InputStream; 11 import java.net.MalformedURLException; 12 import java.net.URL; 13 import java.net.URLConnection; 14 import java.nio.charset.Charset; 15 import java.util.List; 16 import java.util.Map; 17 18 import org.apache.commons.io.IOUtils; 19 20 public class PageEncoding { 21 /** 測試案例 22 * @param args 23 */ 24 public static void main(String[] args) { 25 26 String charset = getEncodingByContentStream("http://www.baidu.com"); 27 28 System.out.println(charset); 29 } 30 31 /** 32 * 從header中擷取頁面編碼 33 * @param strUrl 34 * @return 35 */ 36 public static String getEncodingByHeader(String strUrl){ 37 String charset = null; 38 try { 39 URLConnection urlConn = new URL(strUrl).openConnection(); 40 // 擷取連結的header 41 Map<String, List<String>> headerFields = urlConn.getHeaderFields(); 42 // 判斷headers中是否存在Content-Type 43 if(headerFields.containsKey("Content-Type")){ 44 //拿到header 中的 Content-Type :[text/html; charset=utf-8] 45 List<String> attrs = headerFields.get("Content-Type"); 46 String[] as = attrs.get(0).split(";"); 47 for (String att : as) { 48 if(att.contains("charset")){ 49 // System.out.println(att.split("=")[1]); 50 charset = att.split("=")[1]; 51 } 52 } 53 } 54 return charset; 55 } catch (MalformedURLException e) { 56 e.printStackTrace(); 57 return charset; 58 } catch (IOException e) { 59 e.printStackTrace(); 60 return charset; 61 } 62 } 63 64 /** 65 * 從meta中擷取頁面編碼 66 * @param strUrl 67 * @return 68 */ 69 public static String getEncodingByMeta(String strUrl){ 70 String charset = null; 71 try { 72 URLConnection urlConn = new URL(strUrl).openConnection(); 73 //避免被拒絕 74 urlConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"); 75 // 將html讀取成行,放入list 76 List<String> lines = IOUtils.readLines(urlConn.getInputStream()); 77 for (String line : lines) { 78 if(line.contains("http-equiv") && line.contains("charset")){ 79 // System.out.println(line); 80 String tmp = line.split(";")[1]; 81 charset = tmp.substring(tmp.indexOf("=")+1, tmp.indexOf("\"")); 82 }else{ 83 continue; 84 } 85 } 86 return charset; 87 } catch (MalformedURLException e) { 88 e.printStackTrace(); 89 return charset; 90 } catch (IOException e) { 91 e.printStackTrace(); 92 return charset; 93 } 94 } 95 96 /** 97 * 根據網頁內容擷取頁面編碼 98 * case : 適用於可以直接讀取網頁的情況(例外情況:一些部落格網站禁止不帶User-Agent資訊的訪問請求) 99 * @param url100 * @return101 */102 public static String getEncodingByContentUrl(String url) {103 CodepageDetectorProxy cdp = CodepageDetectorProxy.getInstance();104 cdp.add(JChardetFacade.getInstance());// 依賴jar包 :antlr.jar & chardet.jar105 cdp.add(ASCIIDetector.getInstance());106 cdp.add(UnicodeDetector.getInstance());107 cdp.add(new ParsingDetector(false));108 cdp.add(new ByteOrderMarkDetector());109 110 Charset charset = null;111 try {112 charset = cdp.detectCodepage(new URL(url));113 } catch (MalformedURLException e) {114 e.printStackTrace();115 } catch (IOException e) {116 e.printStackTrace();117 }118 System.out.println(charset);119 return charset == null ? null : charset.name().toLowerCase();120 }121 122 /**123 * 根據網頁內容擷取頁面編碼124 * case : 適用於不可以直接讀取網頁的情況,通過將該網頁轉換為支援mark的輸入資料流,然後解析編碼125 * @param strUrl126 * @return127 */128 public static String getEncodingByContentStream(String strUrl) {129 Charset charset = null;130 try {131 URLConnection urlConn = new URL(strUrl).openConnection();132 //開啟連結,加上User-Agent,避免被拒絕133 urlConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36");134 135 //解析頁面內容136 CodepageDetectorProxy cdp = CodepageDetectorProxy.getInstance();137 cdp.add(JChardetFacade.getInstance());// 依賴jar包 :antlr.jar & chardet.jar138 cdp.add(ASCIIDetector.getInstance());139 cdp.add(UnicodeDetector.getInstance());140 cdp.add(new ParsingDetector(false));141 cdp.add(new ByteOrderMarkDetector());142 143 InputStream in = urlConn.getInputStream();144 ByteArrayInputStream bais = new ByteArrayInputStream(IOUtils.toByteArray(in));145 // detectCodepage(InputStream in, int length) 只支援可以mark的InputStream146 charset = cdp.detectCodepage(bais, 2147483647);147 } catch (MalformedURLException e) {148 e.printStackTrace();149 } catch (IOException e) {150 e.printStackTrace();151 }152 return charset == null ? null : charset.name().toLowerCase();153 }154 }
注意的點:
1.info.monitorenter.cpdetector未在mvn-repository中開源,因而無法從mvn-repository中下載,需要將該jar下到本地,然後手動匯入到本地repository,mvn命令如下:
mvn install:install-file -Dfile=jar包的位置 -DgroupId=該jar的groupId -DartifactId=該jar的artifactId -Dversion=該jar的version -Dpackaging=jar
然後在pom.xml中添加該jar的依賴
<!-- charset detector --><dependency> <groupId>info.monitorenter.cpdetector</groupId> <artifactId>cpdetector</artifactId> <version>1.0.10</version></dependency>
2.JChardetFacade.getInstance()在引入antlr.jar和chardet.jar之前會報異常,在pom.xml中添加這兩個jar的dependency:
<!-- antlr --><dependency> <groupId>antlr</groupId> <artifactId>antlr</artifactId> <version>2.7.7</version></dependency><!-- ChardetFacade --><dependency> <groupId>net.sourceforge.jchardet</groupId> <artifactId>jchardet</artifactId> <version>1.0</version></dependency>
如果是普通項目則無需關心pom.xml,直接把這三個jar包下載下來然後添加到該項目的環境中即可