在爬取内容时,遇到乱码问题。故需对网页内容编码格式做判断,方式大体分为三种:一、从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 url
100 * @return
101 */
102 public static String getEncodingByContentUrl(String url) {
103 CodepageDetectorProxy cdp = CodepageDetectorProxy.getInstance();
104 cdp.add(JChardetFacade.getInstance());// 依赖jar包 :antlr.jar & chardet.jar
105 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 strUrl
126 * @return
127 */
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.jar
138 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的InputStream
146 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包下载下来然后添加到该项目的环境中即可