前言
最近做一个搜索项目,需要爬取很多网站获取需要的信息。在爬取网页的时候,需要获得该网页的编码,不然的话会发现爬取下来的网页有很多都是乱码。
分析
一般情况下,网页头信息会指定编码,可以解析header或者meta获得charset。但有时网页并没没有指定编码,这时就需要通过网页内容检测编码格式,通过调研,最好用的还是cpdetector。
1、首先,可从header中解析charset
网页头信息中的Content-Type会指定编码,如图:
可以通过分析header,查找字符编码,代码如下:
private static String getEncodingByHeader(URL url) {
String strencoding = null;
HttpURLConnection httpConn = null;
try {
httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestProperty("User-agent", "Mozilla/4.0");
Map> map = httpConn.getHeaderFields();
Set keys = map.keySet();
Iterator iterator = keys.iterator();
// 遍历,查找字符编码
String key = null;
String tmp = null;
while (iterator.hasNext()) {
key = iterator.next();
tmp = map.get(key).toString().toLowerCase();
// 获取content-type charset
if (key != null && key.equals("Content-Type")) {
int m = tmp.indexOf("charset=");
if (m != -1) {
strencoding = tmp.substring(m + 8).replace("]", "");
return strencoding;
}
}
}
} catch (IOException e) {
strencoding = null;
} finally {
try {
if (httpConn != null)
httpConn.disconnect();
} catch (Exception ex) {
log.error(ex);
}
}
return strencoding;
}
2、其次,可从网页meta中解析出charset
正常情况下,在写网页时,会指定网页编码,可在meta中读出来。如图:
首先获取网页流,因为英文和数字不会乱码,可以解析meta,获得charset。
/**
* 从网页meta中解析出charset
*
* @param in2
* @return
*/
private static String getEncodingByMeta(InputStream inputs) {
String strencoding = null;
// StringBuffer sb = new StringBuffer();
String line;
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(inputs));
while ((line = in.readLine()) != null) {
// sb.append(line);
if (line.contains("
// 解析html源码,取出区域,并取出charset
line = line.toLowerCase();
String strbegin = "
String strend = ">";
String strtmp;
int begin = line.indexOf(strbegin);
int end = -1;
int inttmp;
while (begin > -1) {
end = line.substring(begin).indexOf(strend);
if (begin > -1 && end > -1) {
strtmp = line.substring(begin, begin + end)
.toLowerCase();
inttmp = strtmp.indexOf("charset");
if (inttmp > -1) {
strencoding = strtmp.substring(inttmp + 7, end)
.replace("=", "").replace("/", "")
.replace("\"", "").replace("\'", "");
//.replace(" ", "#");
if (strencoding.indexOf(" ") != -1) {
strencoding = strencoding.substring(0, strencoding.indexOf(" "));
}
return strencoding;
}
}
line = line.substring(begin);
begin = line.indexOf(strbegin);
}
}
}
} catch (Exception e) {
System.err.println(e);
} finally {
if (in != null)
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
3、当使用1、2解析不出编码时,使用cpdetector根据网页内容探测出编码格式
可以添加多个编码探测实例:
public static String getFileCharacterEnding(URL url) {
String fileCharacterEnding = null;
CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();
detector.add(JChardetFacade.getInstance());// 需要第三方JAR包:antlr.jar、chardet.jar
detector.add(ASCIIDetector.getInstance());
detector.add(UnicodeDetector.getInstance());
detector.add(new ParsingDetector(false));
detector.add(new ByteOrderMarkDetector());
Charset charset = null;
try {
charset = detector.detectCodepage(url);
} catch (Exception e) {
e.printStackTrace();
}
if (charset != null) {
fileCharacterEnding = charset.name();
}
return fileCharacterEnding;
}