2022年 11月 5日

Python的字符编码

编码的发展

 

ASCII字符集

最早的编码机制,由8bit(8位二进制)作为一个字节(byte),一共规定了128个字符和8位二进制数字的对应编码。

GB2312字符集

为兼容庞大的中国汉字开发的字符集,由16bit(16位二进制)即二个字节组成一个数字表示一个特定字符,足够表示256×256=65536个字符。

Unicode字符集

足够兼容所有的字符,属于全世界通用的字符集,是32bit,四个字节表示一个特定字符,我们看到的str类型就是Unicode字符集

UTF-8字符集或GBK字符集

是对Unicode字符集的再次编码,目的是减小Unicode带来的空间浪费问题,实现表示字符的特定二进制数字长度可变。进行数据传送的就是UTF-8字符集或是GBK字符集

Python中的字符串的编码类型和转换

1.类型为str字符串,属于Unicode编码

一般状况下,python默认的编码类型是Unicode,查看字符类型为“str” :

  1. >>> word="世界和平"
  2. >>> print(type(word))
  3. <class 'str'>

2.类型为byte字符串,是对Unicode编码的二进制数据进行再次编码,常见的是UTF-8、GBK

利用encode()将Unicode编码的str类型编码为用UTF-8表示的byte类型:

  1. >>> word_=word.encode("utf-8")
  2. >>> print(word_)
  3. b'\xe4\xb8\x96\xe7\x95\x8c\xe5\x92\x8c\xe5\xb9\xb3'
  4. >>> print(type(word_))
  5. <class 'bytes'>
  6. #\xe4是一个两位的16进制字节,\x是算一个标准吧,在utf8里一个中文字符由3个字节表示

 利用encode()将Unicode编码的str类型编码为用GBK字符集表示的byte类型:

  1. >>> word_=word.encode("GBK")
  2. >>> print(word)
  3. 世界和平
  4. >>> print(word_)
  5. b'\xca\xc0\xbd\xe7\xba\xcd\xc6\xbd'
  6. #在GBK的编码中,2个字节表示一个中文字符

常见的一个报错:用GBK对unicode字符进行编码传输后,却用UTF8进行解码为unicode字符:

  1. >>> word_=word.encode("GBK")
  2. >>> word_.decode("utf8")
  3. Traceback (most recent call last):
  4. File "<stdin>", line 1, in <module>
  5. UnicodeDecodeError: 'utf-8' codec can't decode byte 0xca in position 0: invalid continuation byte
  6. >>>

不能对str类型进行解码,但是可以查看其对应的Unicode字符集的2进制数字:

  1. #ord()函数转换为对应的十进制的字符集编码:
  2. >>> print(ord("世"))
  3. 19990
  4. #bin()函数转为二进制:
  5. >>> bin(19990)
  6. '0b100111000010110' #前面的0b是二进制数字的标记

将UTF-8编码的byte类型字符“\xe4\xb8\x96”转化为2进制:

  1. str_=""
  2. list_=["e4","b8","96"]
  3. for i in list_:
  4. i_=bin(int(i,16))
  5. i__=i_.replace("0b","")
  6. str_+=i__
  7. print(str_)
  8. "111001001011100010010110"

比较字符“世”的UTF-8编码和Unicode编码二进制数值的区别:

  1. #Unicode:
  2. " 0100 111000 010110"
  3. #utf-8:
  4. "11100100 10111000 10010110"

“世”是由三个字符组成,在UTF8的编码规则中,n个字节(n>1)组成的二进制,第1个字节的前n个数字规定为1,第n+1个数字规定为0,其他的字节前两位数是10(……)

和爬虫有关的字符问题

解码方式和响应体编码方式不同出现的报错:

在爬虫过程中,查看响应体自身头部要求的编码格式:

  1. print(response.encoding)
  2. 'ISO-8859-1'

在默认下,爬虫用UTF8作为响应体字符的编码格式,而传输过来的byte类型响应体是根据头部编码信息(可由response.encoding返回)要求进行编码,如上,要是返回“ISO-8859-1”就会出现冲突,就会报错。

解决:告诉python响应体的编码格式:

  1. response=requests.get(link)
  2. response.encoding="GB2312"

报错:illegal multibyte sequence,在一些字符串中混入了非法字符,会直接导致爬虫报错:

解决,用decode()进行解码,添加“ignore”参数忽略非法字符:

  1. #直接获取响应体未解码的字节数据:
  2. byte_datas=response.content
  3. #添加ignore忽略非法字符:
  4. str_datas=byte_datas.decode("GBK","ignore")

网页用gzip进行压缩出现中文乱码的解决

一些网页会对发送的响应体进行压缩,提高发送速度,比如新浪,常见的压缩方式是gzip、deflate

  1. import requests
  2. r=requests.get("https:\\www.sina.com.cn\")
  3. headers={"user-agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3877.400 QQBrowser/10.8.4533.400"}
  4. print(r.text)

若是用get()获取响应体r后,print(r.text)得到的会是一些中文乱码

 幸运的是r.content可以直接解开gzip或deflate的压缩,得到其byte类型数据:

print(r.content)

用chardet根据byte类型数据查看编码方式:

1.安装

pip install chardet --target=C://xx/xx/site-packages

2.查看编码格式

  1. import chardet
  2. print(chardet.detect(r.content))

利用decode()进行解码:

  1. bytes=r.content
  2. strings=bytes.decode("utf8")
  3. print(strings)

参考书籍:python网络爬虫从入门到实践 编者 唐松