【问题】
代码:
输出:
直接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
然后,输出,果然和其一样:
3.对于此现象的原因:
(根据:详解抓取网站,模拟登陆,抓取动态网页的原理和实现(Python,C#等)的:【整理】关于HTML网页源码的字符编码(charset)格式(GB2312,GBK,UTF-8,ISO8859-1等)的解释)
先去确认了所要处理的网页:
中有:
<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的字符串输出,则肯定应该是可以的:
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
结果输出果然是所预测的,正常的:
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
才看到:
当前的,你的PyDev项目,运行期间,所用的console的编码是utf-8
7.对应的,去改为GBK:
然后再点击Run,结果,用之前,将Unicode故意转为UTF-8的话,则输出此时就是,所预料到的,乱码了:
对应的,再去用,最原始的代码,直接输出(得到的GB2312的sina网页),不做任何转换的代码:
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返回的HTML网页(源码)内容:getUrlRespHtml
即可。
【总结】
对于:
Eclipse+PyDev的console,默认是UTF-8,而不是GBK
导致让不熟悉的人误以为,输出GBK(或Unicode)的字符串,
会像输出到GBK的Windows的cmd中一样:
中文不会乱码
如此细节:
- 不熟悉的人,自然很难搞懂背后的逻辑:
- 所以,对于,Python初学者,尤其是对字符编码不是很清楚的人
- -> 也包括对Python字符编码清楚了,但是对于Eclipse不熟悉的人
- -> 也包括,对于Eclipse很熟悉,但是对于PyDev中相关的console编码不熟悉的人
建议:
1.对于字符编码相关知识本身不熟悉,可参考:
复杂教程:
简明教程:
2.不熟悉Python的,自己去看:
3.对于初学者,还是建议先习惯和熟悉普通文件加上cmd去开发Python,熟悉了后,再去用各种IDE。
详细解释见:
4.然后对于Python字符编码方面,不了解的话,再去看:
5.字符编码书序了,Python也熟悉了,Python中的字符编码也熟悉了之后,对于PyDev不熟悉,可参考:
【整理】各种Python的IDE(集成开发环境)的总结和对比
中的:
【记录】使用Python的IDE:Eclipse+PyDev
最终:
等所有相关知识都熟悉了后:
你:
爱用啥Python的IDE,就用啥;
爱怎么折腾IDE的配置,就怎么折腾;
爱怎么写代码,去抓取网页,处理网页,就如何折腾,反正都可以搞定
无论干啥,都是:
先要知道背景知识
然后:
折腾东西,出错后,也才知道,错误的原因到底是啥,以及具体如何解决问题。
转载请注明:在路上 » 【问题解答】python解析网页源代码返回乱码问题