2016.3.3部分
上手爬虫第一天,就遇到了一个麻烦的问题:解码解不出来。
先上源码:
import urllib
import urllib.request
data = {}
data['word'] = 'LEGO'
url_values = urllib.parse.urlencode(data)
url = 'http://www.baidu.com/s?'
full_url = url + url_values
response = urllib.request.urlopen(url)
data = response.read()
data = data.decode('utf8')
print (data)
这段代码就等于是在百度搜索“LEGO”,然后读取搜索到的网页结果。跑一下,发现提示UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbe in position 60: invalid start byte
。上网查了下资料,发现有几三个地方没太搞懂,搞懂了就能解决这个解码问题了:
-
response.read()
返回的到底是什么编码字符?是html的代码对吧,那么这个html代码是用什么方法来编码的呢? -
decode('?')
中需要用什么编码方式才能正确解码?如果知道问题1的答案,那么这个问题2也容易解决了。由于不知道是什么编码方式,那么将?
一个个使用uft8
、big5
、unicode
、gbk
等编码方式尝试,结果都是类似的提示,只是报错的行数不同。 - 我在网上尝试了一下解码后再次编码的方法,变成了
data = data.decode('utf8').encode('gbk')
,看能不能有突破,发现不行后,删掉了后加上的代码,只保留data = data.decode('utf8')
,结果运行.py后还一直提示UnicodeEncodeError: 'gbk' codec can't encode character '\xbb' in position 25145: illegal multibyte sequence
,最后只能是将整行注释掉才恢复正常(输出html源码),但去掉注释后又弹出encode提示,代码中明明没有了encode啊!我的内心几乎是崩溃的!
在继续查资料后,决定先放下这个解码问题,先做好数据存储那一块,再回头慢慢解决切割和解码问题,没准到时候就懂了。
2016.3.10部分
在使用了Requests和BeautifulSoup第三方库后,打算将爬到的数据打印出来看一下:
import requests
import urllib.parse
from bs4 import BeautifulSoup
response = requests.get('http://www.baidu.com')
soup = BeautifulSoup(response.text, "html.parser")
print (soup.title.text)
print (soup.body.text)
结果,还是报了跟之前一样的编码错误:UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' in position 12734: illegal multibyte sequence
,于是继续查,终于找到原因了。
解决方法如下:
- 忽略cmd的显示问题,直接存为文件输出
其实呢,这是windows控制台本身的显示编码, 在dos窗口标题,右键菜单选择属性,可以看到控制台的默认编码为GBK(cp936)。
所以说,问题不在python,不在网页,而是那个呆板的dos控制台。
解决方法呢,简单点可以写到本地文件中查看,复杂点的就留给你去折腾了。 注意,这只是dos控制台的显示问题,对于其中字符串的处理完全不受阻碍。 看不看得见,它就在内存里,该干嘛还干嘛。
- 使用函数将爬取的数据保存为文件
def save_file(data, path):
files = open(path, 'wb')
files.write(data)
files.close()
save_file(soup.title.text, 'p7_title.txt')
save_file(soup.body.text, 'p7_body.txt')
- 结果报了另外一个错:
TypeError: a bytes-like object is required, not 'str'
,那么再对爬到的数据使用strip再encode的方法
save_file(soup.title.text.strip('\00').encode(), 'p7_title.txt')
save_file(soup.body.text.strip('\00').encode(), 'p7_body.txt')
- 如此一来,虽然是绕弯解决的,没有直面问题,但还是顺利解决了问题,并且已经拿到了需要的数据。
相关资料
- 关于Python打印网页内容时报错