JavaScript-如何高效、准确、自动识别网页编码
我知道的有两种途径获取网页的编码信息:
其一、通过服务器返回的header里的charset变量获取
其二、通过页面里的meta 信息获取
正常情况下,如果服务器或者页面有提供这两个参数,而且参数是正确的。
但是现实抓取网页时,经常会出现以下几种情况:
1.这两个参数缺失了
2.这两个参数虽然都提供了,但是不一致
3.这两个参数提供了,但是与网页实际的编码不一致
我现在通过php里面有个mb_detect函数,貌似识别字符串编码,但他的准确率就不好说了,因为编码的自动识别是一个概率事件,只有当被识别的字符串的长度足够大( 比如超过300个字)时,才能比较可靠。
除了这个之外,还有其它方式可以实现吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
希望这两个函数能对你有点帮助:
判断是否是utf8编码
function is_utf8($word)
{
return (preg_match("/^([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}/",$word) == true || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}$/",$word) == true || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){2,}/",$word) == true);
}
判断是否是gb2312编码
function is_gb2312($str)
{
for($i=0; $i<strlen($str); $i++) {
$v = ord( $str[$i] );
if( $v > 127) {
if( ($v >= 228) && ($v <= 233) )
{
if( ($i+2) >= (strlen($str) - 1)) return true; // not enough characters
$v1 = ord( $str[$i+1] );
$v2 = ord( $str[$i+2] );
if( ($v1 >= 128) && ($v1 <=191) && ($v2 >=128) && ($v2 <= 191) ) // utf编码
return false;
else
return true;
}
}
}
return true;
}
使用由mozzila提供的universalchardet模块,据说比IE自带的识别模块准确率高很多。
universalchardet项目的地址在:http://www-archive.mozilla.org/projects/intl/chardet.html
目前universalchardet支持python java dotnet等
C#版本:
http://code.google.com/p/nuniversalchardet/
具体参考这篇文章:
http://www.cnblogs.com/tdlian/archive/2011/11/25/2263054.html
这篇文章提供了各种语言的移植,遗憾的是没有发现PHP的移植:
http://www.byvoid.com/blog/tag/universalchardet/
我说下原理哈,我们知道如何HTTP协议中如果没有指定编码的情况下,这时候浏览器所用的方法是统计,统计其实就是猜,每种情况去取一定的字符数,对每种的编码都做统计,概率性高的就命中,不过为了提高统计速度,统计应该先从几种常用的字符串开始ANSIIC、UTF8、UNICODE,除了这个之外服务器在抓取网页内容时,可以先通过IP猜测所属的国家,然后根据国家找到对应的编码,这样效率会提高很多。
java使用cpdetector进行编码自动识别,识别率比较高
下载链接:http://sourceforge.net/projects/cpdetector/files/?source=navbar
使用实例:
import info.monitorenter.cpdetector.io.ASCIIDetector;
import info.monitorenter.cpdetector.io.CodepageDetectorProxy;
import info.monitorenter.cpdetector.io.JChardetFacade;
import info.monitorenter.cpdetector.io.ParsingDetector;
import info.monitorenter.cpdetector.io.UnicodeDetector;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EncodingDetector {
private static final Logger log = LoggerFactory .getLogger(EncodingDetector.class);
private static final CodepageDetectorProxy detector = CodepageDetectorProxy .getInstance();
static {
/*-------------------------------------------------------------------------
ParsingDetector可用于检查HTML、XML等文件或字符流的编码,构造方法中的参数用于
指示是否显示探测过程的详细信息,为false不显示。
---------------------------------------------------------------------------*/
detector.add(new ParsingDetector(false));
/*--------------------------------------------------------------------------
JChardetFacade封装了由Mozilla组织提供的JChardet,它可以完成大多数文件的编码
测定。所以,一般有了这个探测器就可满足大多数项目的要求,如果你还不放心,可以
再多加几个探测器,比如下面的ASCIIDetector、UnicodeDetector等。
---------------------------------------------------------------------------*/
detector.add(JChardetFacade.getInstance());
// ASCIIDetector用于ASCII编码测定
detector.add(ASCIIDetector.getInstance());
// UnicodeDetector用于Unicode家族编码的测定
detector.add(UnicodeDetector.getInstance());
}
public static String getCharset(File file) {
Charset charset = null;
try {
charset = detector.detectCodepage(new BufferedInputStream(new FileInputStream(file)),1000);
log.info("file [{}] > charset:{}", file, null != charset ? charset.name() : null);
} catch (Exception e) {
log.info("file [{}] error > ", file, e);
}
return null != charset ? charset.name() : null;
}
public static String getCharset(InputStream is) {
Charset charset = null;
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(is);
charset = detector.detectCodepage(bufferedInputStream,1000);
bufferedInputStream.reset();
} catch (Exception e) {
}
return null != charset ? charset.name() : null;
}
}