存储html,coding问题

最近在使用selenium来抓取网页,保存page_source的时候,遇到coding问题,试验并总结如下:
Python版本: 2.7.12

第一种情况

driver.get('http://bbs.chinaunix.net/forum-24-1.html')
doc = driver.page_source  # unicode
with codecs.open('web.html', mode='w') as f:
    f.write(doc)

这种情况会有如下错误:

Traceback (most recent call last):
  File "/home/cooli7wa/PycharmProjects/untitled/web.py", line 22, in 
    f.write(doc)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 327-332: ordinal not in range(128)

存储文件的时候,如果文件未encode,比如上面的情况,page_source得到的是unicode格式代码,那么python会选择默认的ascii格式来encode,ascii无法支持中文,故出错。

更改下代码,采用utf-8来encode:

driver.get('http://bbs.chinaunix.net/forum-24-1.html')
doc = driver.page_source  # unicode
with codecs.open('web.html', mode='w',encoding='utf-8') as f:
    f.write(doc)
# 或者
with codecs.open('web.html', mode='w') as f:
    f.write(doc.encode('utf-8'))

运行正确。

第二种情况

使用BeautifulSoup来美化html格式:

driver.get('http://bbs.chinaunix.net/forum-24-1.html')
doc = driver.page_source  # unicode
soup = bs(doc)  # utf-8
prettyhtml = soup.prettify()  # utf-8
with codecs.open('web.html', mode='w', encoding='utf-8') as f:
    f.write(prettyhtml)

这段代码运行,出错如下:

Traceback (most recent call last):
  File "/home/cooli7wa/PycharmProjects/untitled/web.py", line 23, in 
    f.write(prettyhtml)
  File "/usr/lib/python2.7/codecs.py", line 706, in write
    return self.writer.write(data)
  File "/usr/lib/python2.7/codecs.py", line 369, in write
    data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 345: ordinal not in range(128)

decode失败
这个是由于BeautifulSoup之后的格式是utf-8,不再是unicode,codecs指定了需要使用utf-8来encode,但是python并不知道原来就是utf-8格式,所以它需要先decode(使用默认的ascii)到unicode再encode(使用指定的utf-8)到utf-8,所以这里utf-8格式的文件在使用ascii decode的时候失败了。

这里有几种方式来解决这个问题:

# 不指定codecs的encode格式,这时python发现原来文件已经是encode过的,那么就不进行decode encode操作
driver.get('http://bbs.chinaunix.net/forum-24-1.html')
doc = driver.page_source  # unicode
soup = bs(doc)  # utf-8
prettyhtml = soup.prettify()  # utf-8
with codecs.open('web.html', mode='w') as f:
    f.write(prettyhtml)

# 或者,先将utf-8自己手动decode到unicode格式
driver.get('http://bbs.chinaunix.net/forum-24-1.html')
doc = driver.page_source  # unicode
soup = bs(doc)  # utf-8
prettyhtml = soup.prettify().decode('utf-8')  # unicode
with codecs.open('web.html', mode='w', encoding='utf-8') as f:
    f.write(prettyhtml)

都可以运行通过

总结

这里面出错的根本原因,都是python默认的ascii编码太low,不支持中文。
所以有一种通用的解决方法:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

这种更改了默认的encode和decode方式,问题就解决了,但是有时了解下问题原因也很重要。

一些额外的东西

1、#coding:utf-8 与 sys.setdefaultencoding(‘utf-8’)

引用一段解释:
第一行那个不是代码,不会执行的,只影响Python解释器读取源文件时候使用的编码。比如你在代码里面写了’中文’这样的字符串,默认是读不出来的,因为不是ascii字符,所以要指定文件编码是utf-8(当然文件也要用utf-8格式保存)。等读到内存里变成’\xe4\xb8\xad\xe6\x96\x87’之后就没有区别了。 下面那个设置的是Python运行时的字符默认编码,完全是另一回事。Python2.x为了兼容处理Unicode字符串(unicode)和ANSI字符串str,某些时候会自动做两者的转换,但默认使用的是ASCII字符编码,如果有utf-8字符在里面就会出错。这个hack是修改这个默认特性。非常不建议这么做,你应该永远分清str(bytes)和unicode,然后自己调用encode、decode来转换。Python3.x下这两个类型已经不兼容了。

2、怎么才能尽量避免编码问题

Python2编码问题的根源是混淆使用str和unicode(这在Python3中会直接报错),因为Python2会自动帮忙转换格式,所以有时程序跑起来没有问题,但是有时就会出现UnicodeError
这篇文章讲得很好http://pycoders-weekly-chinese.readthedocs.io/en/latest/issue5/unipain.html

总结有以下几点:
- Unicode 三明治:尽可能的让你程序处理的文本都为 Unicode 。
- 了解你的字符串。你应该知道你的程序中,哪些是 unicode, 哪些是 byte, 对于这些 byte 串,你应该知道,他们的编码是什么。
- 测试 Unicode 支持。使用一些奇怪的符号来测试你是否已经做到了以上几点。

你可能感兴趣的:(Opencv)