posts - 16,  comments - 17,  trackbacks - 0

  关于idhttp取网页源码编码问题,在这里记录最后一次的解决方法,不想再纠结下去,再也伤不起了。(本文内容均在d2010,indy10.55的环境下产生及结束)。

  网上只要搜索关于idhttp取网页乱码,idyttp编码问题的文章有一大堆,试了无数,都不满意,最后再这里记录一下个人解决方法。

  在IDE中写如下代码,str:=http.get(xxxxx);然后Ctrl跟踪get,会在源码中得到如下一行,也是最关键的一行:

Result := ReadStringAsCharset(LResponse, Response.CharSet);

很明显,idhttp想给我们做点好事,直接返回解码后(能正常阅读、没有乱码)的内容,问题来了,当Response.CharSet有值时,返回的内容是完全正确的,当Response.CharSet没有值时,返回的结果值得商榷了。所以就有了网上常有人问的“为什么在UTF-8的情况下,返回内容是正常的,但是GBK的就不行了?”,经我测试,当网页是UTF-8时,Response.CharSet='utf-8',当网页是GBK时,Response.CharSet就不一定是GBK,很多时候都是空的,这时候,在使用上面的函数时,CharSet默认为西欧(可能吧)编码,得到的内容比UTF-8编码后的结果更难看懂。所以,我们要做的,就是给CharSet一个可用的、正确的值。

  如果得到一个可用的、正确的CharSet值呢?首先,idhttp.Response.CharSet这个是首选的,如果这个值为空呢,就需要在返回的HTML中找了,如:

<html> 
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>执行 Application.Terminate 后, OnDestroy 中的代码还会执行 - 万一 - 博客园</title>
<link type="text/css" rel="stylesheet" href="http://www.cnblogs.com/css/common.css"/>

在上面代码中醒目的部分,charset=utf-8,我们要的就是这个,这部分是英文,所以不管什么编码,都能正常得到这部分内容,需要做的就是用正则把charset=后面的内容取出,再判断具体的编码,一般只需要考虑两种情况:utf-8和gbk,实现代码如下:

function Txxxxxx.getMethod(AURL: string): string;
var
LResponse: TMemoryStream;
LEncoding:TIdTextEncoding;
per:TPerlRegEx;
begin
LResponse := TMemoryStream.Create;
try
try
http.Get(AURL, LResponse);
finally
http.Disconnect;
end;
LResponse.Position := 0;
if http.Response.CharSet<>'' then
begin
LEncoding := CharsetToEncoding(http.Response.CharSet);
if AnsiSameText(http.Response.CharSet,'utf-8') then
isutf8:=true
else isutf8:=False;
end
else
begin
LEncoding := TEncoding.Default;
Result := ReadStringFromStream(LResponse, -1, LEncoding);

per:=TPerlRegEx.Create(nil);
per.Options:=[preCaseLess];
per.Subject:=Result;
per.RegEx:='<meta[\S\s]*?charset=(.*)>';
if per.Match then
begin
if AnsiContainsText(per.MatchedExpression,'utf-8') then
begin
isutf8:=true;
LEncoding := CharsetToEncoding('utf-8');
end
else
begin
isutf8:=False;
LEncoding := CharsetToEncoding('gbk');
end;
end;
FreeAndNil(per);
end;
LResponse.Position := 0;
Result := ReadStringFromStream(LResponse, -1, LEncoding);
finally
FreeAndNil(LResponse);
end;
end;

我承认,我欺骗了你,因为在上面的代码中,我没有给CharSet找一个正确的值,而是用到了IdGlobal, IdGlobalProtocols中的两个函数,直接返回一个理想的内容,就像你看到的,首先,需要一个http:IDHTTP和isutf8:boolean,然后直接调用 str:=GetMethod(xxxxxx)就可以得到内容了。

  通过如上方法,能解决80%的网页编码问题,为什么不是100%呢,因为还有一部分的网页,通过idhttp.get,你会发现Response.CharSet='',并且在HTML中没有设置编码的meta标签,如果这种情况,请不要纠结,略过它吧。。。。

  注明:本文只适合菜鸟阅读,也欢迎高手拍砖。



posted on 2012-02-20 16:58 Bach 阅读(...) 评论(...) 编辑 收藏