【问题解答】python解析网页源代码返回乱码问题

【问题】

python解析网页源代码返回乱码问题

代码:

ask python pydev console code

输出:

ask python pydev console messy output

直接print中文是可以的,注释的中文也不会乱码,就解析网页乱码
求有用解决方案!!

【问题解答】

从问题现象到问题本质,一点点帮你分析为何如何,以及如何解决问题

1.首先,根据之前的Python的IDE的经验:

【整理】各种Python的IDE(集成开发环境)的总结和对比

从上述截图,基本上,可以推测出来,其用的是:

【记录】使用Python的IDE:Eclipse+PyDev

2.所以,为了完全重现其问题,专门去PyDev中建立了对应的项目。

代码为:

# -*- coding: utf-8 -*- 
'''
Created on Oct 18, 2013

@author: CLi
'''
from urllib import urlopen

def getHtml(url):
    page = urlopen(url)
    html = page.read()
    page.close()
    return html

if __name__ == "__main__":
    url = "http://www.sina.com.cn"
    html = getHtml(url)
    print html

然后,输出,果然和其一样:

pydev console output messy cn chars

3.对于此现象的原因:

(根据:详解抓取网站,模拟登陆,抓取动态网页的原理和实现(Python,C#等)的:【整理】关于HTML网页源码的字符编码(charset)格式(GB2312,GBK,UTF-8,ISO8859-1等)的解释

先去确认了所要处理的网页:

http://www.sina.com.cn/

中有:

<meta http-equiv="Content-type" content="text/html; charset=gb2312" />

(再根据:字符编码简明教程

可知,此处的代码处理中,如果需要解码为Unicode,最好用GBK。

而此处得到的sina网页的字符串,是GB2312

对应的,在Eclipse+PyDev中的console中输出,结果却乱码了。

则可以确定:

Eclipse+PyDev的console中,所用字符编码不是GB2312(也不是GBK或GB18030)

猜测:

估计是用的,相对常见的,UTF-8

4.但是不管其用什么编码,将Unicode的字符串输出,则肯定应该是可以的:

after decode to unicode output ok

5.为了验证上面的PyDev的console是UTF-8的猜测,所以去用代码:

# -*- coding: utf-8 -*- 
'''
Created on Oct 18, 2013

@author: CLi
'''
from urllib import urlopen

def getHtml(url):
    page = urlopen(url)
    html = page.read()
    page.close()
    #uniCodehtml = html.decode("GBK")
    #return uniCodehtml
    
    uniCodehtml = html.decode("GBK")
    utf8html = uniCodehtml.encode("UTF-8")
    return utf8html

if __name__ == "__main__":
    url = "http://www.sina.com.cn"
    html = getHtml(url)
    print html

结果输出果然是所预测的,正常的:

after encode to utf8 still ouput ok

6.接下来,就很明显了:

需要搞清楚,为何此处:

Eclipse+PyDev的Console中,

(不是我们之前所以为的,调用了Windows的cmd,以为是GBK编码)

却是UTF-8编码

然后参考:

Printing Unicode in eclipse Pydev console and in Idle

而去看看:

结果在Eclipse的Window->Preferences中,找了半天,都没有找到关于console的encoding方面的设置。

最后是在:

选择你的PyDev项目->Run->Run Configuration-> Python Run ->选择你当前的PyDev项目->Common->Encoding

eclipse pydev run run configuration

run configuration python run common encoding is utf8

才看到:

当前的,你的PyDev项目,运行期间,所用的console的编码是utf-8

7.对应的,去改为GBK:

change pydev console from utf8 to gbk

然后再点击Run,结果,用之前,将Unicode故意转为UTF-8的话,则输出此时就是,所预料到的,乱码了:

last unicode to utf8 now messy

对应的,再去用,最原始的代码,直接输出(得到的GB2312的sina网页),不做任何转换的代码:

use original got sina gb2312 direct output to pydev console now ok

8.由此,可以完全明白原因了:

(1)从sina获得的html网页,这个字符串,本身的字符编码为:GB2312

(2)直接print输出到,Eclipse+PyDev,中的console时,由于console默认是UTF-8编码,所以:

将GB2312的sina的html网页字符串输出到UTF-8的Eclipse+PyDev的console中

必然导致乱码。

而由于前面多次的尝试可知,解决办法有多种:

(1)代码不改:

from urllib import urlopen

def getHtml(url):
    page = urlopen(url)
    html = page.read()
    page.close()
    return html

if __name__ == "__main__":
    url = "http://www.sina.com.cn"
    html = getHtml(url)
    print html

但是去改,Eclipse+PyDev的console的字符编码,从UTF-8改为GBK(或GB2312,或GB18030):

选择你的PyDev项目->Run->Run Configuration-> Python Run ->选择你当前的PyDev项目->Common->Encoding->改为GBK

 

(2)不改Eclipse+PyDev的console的字符编码,仍保持旧的UTF-8的配置,但是去改代码:

from urllib import urlopen

def getHtml(url):
    page = urlopen(url)
    html = page.read()
    page.close()
    
    uniCodehtml = html.decode("GBK")
    return uniCodehtml

if __name__ == "__main__":
    url = "http://www.sina.com.cn"
    html = getHtml(url)
    print html

即,获得GB2312的html后,去decode为Unicode,然后直接输出Unicode字符串到UTF-8的Eclipse+PyDev的console中,

则比如也是可以正常显示无乱码的

(内部会自动将输出的Unicode转换为当前console的UTF-8编码的字符串的)

(3)基于上面那种方式,(不改Eclipse+PyDev的console的字符编码,仍保持旧的UTF-8的配置),但是在转换为Unicode后,再故意转为输出目标(此处的Eclipse+PyDev的console)的编码,即UTF-8:

from urllib import urlopen

def getHtml(url):
    page = urlopen(url)
    html = page.read()
    page.close()
    #uniCodehtml = html.decode("GBK")
    #return uniCodehtml
    
    uniCodehtml = html.decode("GBK")
    utf8html = uniCodehtml.encode("UTF-8")
    return utf8html

if __name__ == "__main__":
    url = "http://www.sina.com.cn"
    html = getHtml(url)
    print html

也是可以保证输出的网页是正常的,中文不是乱码。

 

 

关于返回的网页是否要解压缩

另外,有人提到的:

(以为此处获得的网页是压缩的)

所以需要对于抓取回来的网页进行解压缩

此处实际结果证明了:

是不需要的。

其背后的原理和逻辑是:

(正常情况下)只有当你抓取网页所提交的请求,包含了说你支持(即需要)返回压缩的网页

(人家服务器)才返回对应的压缩的网页

详见:

【总结】静态网页抓取,动态网页抓取,模拟登陆的注意事项和心得

中的:“返回的html内容是二进制的乱码”

 

进一步分析问题的现象和背后的本质

至此,上面的所有分析,还只是:

和解压代码无关,和字符串编码有关

但是:

此处,才注意到,提问者提问所截的图

看起来,还的确是:

打印出来的乱码

像是二进制级别的字符串乱码

而非之前所讨论的,中文的乱码

此刻,猜测问题最大的可能性是:

提问者,没有给出背后相关的其所用的所有的代码

估计其代码,除了此处截图给出的代码之外

还是在别处,用到了对应的:

【总结】静态网页抓取,动态网页抓取,模拟登陆的注意事项和心得

中的:“返回的html内容是二进制的乱码”

所提到的:

添加了对应的头信息,其中包含了:

Accept-Encoding设置了gzip,deflate

从而导致:

此处,返回的网页,直接打印出现二进制那种的乱码

(而不是字符编码设置错误的,只会导致中文异常的那种乱码)

所以:

  • 要么是我上述推测错了;
  • 要么是,我推测是对的,而提问者,没有给出错误现象背后的,相关的所有的代码和背景条件
    • -> 导致上面耗费半天时间分析编码错误导致中文乱码,对于此问题来说,算是白费功夫了
      • -> 当然对于其他人不熟悉的此方面内容的,肯定还是有参考意义的

无论哪种情况,此种,二进制乱码

的解决办法是:

核心相关代码:

#print "---before unzip, len(respHtml)=",len(respHtml);
respInfo = resp.info();
  
# Server: nginx/1.0.8
# Date: Sun, 08 Apr 2012 12:30:35 GMT
# Content-Type: text/html
# Transfer-Encoding: chunked
# Connection: close
# Vary: Accept-Encoding
# ...
# Content-Encoding: gzip
  
# sometime, the request use gzip,deflate, but actually returned is un-gzip html
# -> response info not include above "Content-Encoding: gzip"
# eg: http://blog.sina.com.cn/s/comment_730793bf010144j7_3.html
# -> so here only decode when it is indeed is gziped data
  
#Content-Encoding: deflate
if("Content-Encoding" in respInfo):
    if("gzip" == respInfo['Content-Encoding']):
        respHtml = zlib.decompress(respHtml, 16+zlib.MAX_WBITS);
    elif("deflate" == respInfo['Content-Encoding']):
        respHtml = zlib.decompress(respHtml, -zlib.MAX_WBITS);

更详细的解释,参见:

【总结】静态网页抓取,动态网页抓取,模拟登陆的注意事项和心得

中的:“返回的html内容是二进制的乱码”

 

对应的,很明显,上面的核心代码,

本来就无需,无法,直接加入到,此处提问者所贴出的那段代码的:

因为:

其所给出的代码,根本就不应该存在此问题才对。

 

更加,功能丰富的,用于抓取网页的函数,其实我早就帮你们封装好了,只是你们不知道,没去用而已。

感兴趣的,自己去看:

获得Url地址的响应:getUrlResponse

和:

获得Url返回的HTML网页(源码)内容:getUrlRespHtml

即可。

 

【总结】

对于:

Eclipse+PyDev的console,默认是UTF-8,而不是GBK

导致让不熟悉的人误以为,输出GBK(或Unicode)的字符串,

会像输出到GBK的Windows的cmd中一样:

中文不会乱码

如此细节:

  • 不熟悉的人,自然很难搞懂背后的逻辑:
    • 所以,对于,Python初学者,尤其是对字符编码不是很清楚的人
      • -> 也包括对Python字符编码清楚了,但是对于Eclipse不熟悉的人
        • -> 也包括,对于Eclipse很熟悉,但是对于PyDev中相关的console编码不熟悉的人

建议:

1.对于字符编码相关知识本身不熟悉,可参考:

复杂教程:

字符编码详解

简明教程:

字符编码简明教程

2.不熟悉Python的,自己去看:

python初级教程:入门详解

3.对于初学者,还是建议先习惯和熟悉普通文件加上cmd去开发Python,熟悉了后,再去用各种IDE。

详细解释见:

总结:到底使用哪种环境去开发Python

4.然后对于Python字符编码方面,不了解的话,再去看:

Python专题教程:字符串和字符编码

5.字符编码书序了,Python也熟悉了,Python中的字符编码也熟悉了之后,对于PyDev不熟悉,可参考:

【整理】各种Python的IDE(集成开发环境)的总结和对比

中的:

【记录】使用Python的IDE:Eclipse+PyDev

 

最终:

等所有相关知识都熟悉了后:

你:

爱用啥Python的IDE,就用啥;

爱怎么折腾IDE的配置,就怎么折腾;

爱怎么写代码,去抓取网页,处理网页,就如何折腾,反正都可以搞定

 

无论干啥,都是:

先要知道背景知识

然后:

折腾东西,出错后,也才知道,错误的原因到底是啥,以及具体如何解决问题。



发表评论

电子邮件地址不会被公开。 必填项已用*标注

无觅相关文章插件,快速提升流量