python编码问题

以抓取网易图片的程序为例说明python的编码问题,主要涉及python中文乱码,unicode和str类型转换,python解释器处理编码方式等问题。

 1 #coding:utf-8
 2 import sys 
 3 reload(sys) 
 4 sys.setdefaultencoding('utf-8') 
 5 
 6 import re
 7 import requests
 8 import os
 9 import urllib
10 
11 def down_pic(url):
12     pic_html = requests.get(url)
13     if pic_html.status_code == 200:
14         pic_html_text = pic_html.text
15         #print pic_html.encoding
16         #print pic_html_text
17 
18         #获取所有图片url,选择图片均为大图
19         pic_gallery_patt = r'"oimg": "(.+?.jpg)"'
20         #获取图片链接的主题
21         title_patt = r'<title>(.+?)</title>'
22         #获取图片的名称
23         img_name_patt = r'"id": "(.+?)",'
24 
25         img_text = re.findall(pic_gallery_patt, pic_html_text)
26         title_name = re.findall(title_patt, pic_html_text)
27         file_name = re.findall(img_name_patt, pic_html_text)
28 
29         #创建文件夹,需要处理转义符
30         curr_path = os.getcwd()
31         curr_path = curr_path.replace('\', '/')
32         file_dir = curr_path + '/'
33         if os.path.exists(file_dir):
34             file_dir += title_name[0]        
35         file_dir += '/'
36         #curr_path 是str类型,title_name[0]是unicode类型
37         #print type(file_dir)
38         #直接将unicode作为参数传入mkdir()方法,Python将先使用源代码文件声明的字符编码进行编码然后写入
39         os.mkdir(file_dir)
40         
41         print '开始下载......'
42 
43         for dic in zip(img_text,file_name):
44             #requests模块抓取的网页内容为unicode类型,可以用encode可以转换为utf-8编码的str类型
45             img_utf8_url = dic[0]
46             #生成图片存储路径
47             file_name_str = dic[1]
48             file_type = ".jpg"
49             #unicode类型和str类型连接生成新对象为unicode类型
50             filepath = file_dir + file_name_str + file_type           
51             print img_utf8_url, filepath  
52             #filepath为unicode类型,normcase函数会把filepath自动处理成系统可以使用的字符串
53             #filepath = os.path.normcase(filepath)         
54             urllib.urlretrieve(img_utf8_url, filepath)
55 
56         print '下载完成......'
57 
58 
59 if __name__ == '__main__':
60     pic_url = r'http://news.163.com/photoview/00AP0001/37116.html?from=tj_day#p=96A9I01H00AP0001'
61     down_pic(pic_url)

1.python中的str和unicode

  首先,程序的第一步是用requests模块获取网页,pic_html.text获得响应内容,以 unicode表示(如果用pic_html.content,内容将以bytes表示)。

file_dir += title_name[0]是为了生成文件目录,但是file_dir是str类型,title_name[0]是unicode类型,连接之后是什么类型呢?用type函数查看file_dir发现是unicode类型。说明一个unicode类型和str类型连接得到的是unicode类型。

  下面解释一下str和unicode:

  str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。对UTF-8编码的str'汉'使用len()函数时,结果是3,因为实际上,UTF-8编码的'汉' == 'xE6xB1x89'。

  unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u'汉') == 1。

  我们看一下unicode的解释:

  Unicode字符串
  Unicode是书写国际文本的标准方法。如果你想要用你的母语如北印度语或阿拉伯语写文本,那么你需要有一个支持Unicode的编辑器。类似地,Python允许你处理Unicode文本——你只需要在字符串前加上前缀u或U。例如,u"This is a Unicode string."。

  记住,在你处理文本文件的时候使用Unicode字符串,特别是当你知道这个文件含有用非英语的语言写的文本。  

  str其实是字节串,它是unicode字符串经过编码(encode)后的字节组成的序列。unicode是str字符串经过解码(encode)后的字符串
  encode和decode的使用:

  (unicode字符串).encode是指将unicode转换成其他格式的编码
  例:u'中文'.encode('utf8')将unicode字符串(u'中文')转换成utf8编码

  (str字符串).decode是指将其他格式的编码转换成unicode
  例:'中文'.decode('utf8')将utf8字符串转换成unicode编码

  就像下面这样使用

1 s = '你好'
2 print s
3 s.decode('utf-8')
4 print s
5 s1 = u'你好'
6 print s1
7 s1 = s1.encode('utf-8')
8 print s1

  但是如果你直接在IDLE这样用就会报错,因为终端的默认编码设置为ascii,即s的编码是ascii,然而decode('utf-8')却是将utf8字符串转换成unicode编码。

  如果decode('ascii')呢?由于ASCII无法将中文转成unicode,所以它仍然会报错了。

  2. python中文乱码

1 s1 = u'你好'
2 print s1
3 s1 = s1.encode('utf-8')
4 print s1

  在IDLE中,print s1会输出乱码,因为print只是把字节串传递给操作系统,而由操作系统决定以何种编码输出。对于unicode,就依赖于stdout的输出编码。由于stdout的默认输出编码为ascii,所以出错。同样s1转码后,以ascii编码输出utf8编码的字符串也会出错。

  如果你要处理的程序中有中文,最好在开头加上:

1 #coding:utf-8  
2 import sys 
3 reload(sys) 
4 sys.setdefaultencoding('utf-8') 

  推荐utf-8,不推荐cp936。

  建议: 使用字符编码声明,并且同一工程中的所有源代码文件使用相同的字符编码声明。

  如果你用sublime text2编写python程序,可能sublime text2已经把编码默认设为utf-8。但是为了万无一失,同样在文件头加上上述代码。

  不管是str还是unicode,字符串在python内部的表示都是unicode编码,它相当于一种统一的中间编码。所以经常会需要从其他编码成unicode,或者从unicode解码到其他编码。这就意味着,对于代码文件,或者其他内容,不管这些内容的编码是ASCII还是UTF-8,python都会把这些内容转换成它所接受的编码—即unicode。
  python解析器读取代码文件本身时,会试图把它转成unicode。但是上面的代码文件中出现了中文,并且文件头上没有任何的编码声明,python就会试图采用默认的ASCII编码来把中文转成unicode,但是显然,ASCII无法将中文转成unicode,所以它报错了。
  在文件的第一行加上声明:#coding=编码字符串,注意声明的编码必须与文件实际保存的编码一致

  3.什么os.mkdir()和urllib.urlretrieve(url, filepath)能够接受unicode类型?

   可以参考对python读写文件的解释:

  open()打开文件时,read()读取的是str,读取后需要使用正确的编码格式进行decode()。
  write()写入文件时,如果参数是 unicode,则需要使用你希望写入的编码进行encode();如果是其他编码格式的str,则需要先用该str的编码进行decode(),转成 unicode后再使用写入的编码进行encode();如果直接将unicode作为参数传入write()方法,Python将先使用源代码文件声明的字符编码进行编码然后写入。

  os.mkdir()和urllib.urlretrieve(url, filepath)同理。

原文地址:https://www.cnblogs.com/lkprof/p/3260773.html