\'gbk\' codec can\'t encode character解决方法
用了一上午的时间做了个这个,还是比较简单的。多练练,总会进步。遇到了很多问题,庆幸自己都解决了。
我的过程是:(python3)
1、先将豆瓣读书的所有标签以每行七个打印到页面上。
2、输入要爬取标签的名字,可以输入多个。
3、输入你想要爬取多少页。
4、爬取每本书的书名、作者、出版社、评分、评价人数、图书的url,封面图片的url
5、以标签名作为文件名存到本地文件中。(本来想保存到Excel中的,但是我下载的Python是最新版本,自己知道的库中,没有合适的)
6、把这些用到我练习的网站(用的Django)中,在Django下写一个脚本,将数据导入数据库
import time import random import requests from bs4 import BeautifulSoup def printTag(): \'\'\' 以每行七个、打印标签名, :return: \'\'\' response = requests.get(\'https://book.douban.com/tag/?view=cloud\') soup = BeautifulSoup(response.text, \'lxml\') tags = soup.select(\'.tagCol td a\') tag_list = [] start = 0 end = 7 for tag in tags: tag_list.append(tag.get_text()) tr, td = divmod(len(tag_list), 7) # print(tr, td) if td != 0: tr = tr + 1 for i in range(tr): print(tag_list[start:end]) start, end = end, end + 7 def devideTag(book_tag_list): # 操作全局变量 global START_PAGE for book_tag in book_tag_list: # 每个标签下的书籍 bookSpider(book_tag) # 每爬完一个标签,将起始页归为1 START_PAGE = 1 def bookSpider(book_tag): global START_PAGE # 设置请求头 headers = { \'User-Agent\': \'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36\'} # 设置循环终止条件,小于你要爬取的页数,或遇到错误终止 while START_PAGE <= int(end): # 分析一下url ,找规律 param = \'start=\' + str((START_PAGE - 1) * 20) + \'&type=T\' url = url = \'https://book.douban.com/tag/%s/\' % book_tag # 休息一下,哈哈 time.sleep(random.random() * 5) # 如果网址有错误,报错、退出 try: # 拼接url response = requests.get(url, params=param, headers=headers) except Exception as e: print(e) break # 用Beautifulsoup解析这个页面 soup = BeautifulSoup(response.text, \'lxml\') # 这个页面是否有内容,如果没有退出 try: content = soup.find_all(\'li\', class_=\'subject-item\') except: print(\'此页无内容\') break # 获取你想要的数据 loadData(content, book_tag) def loadData(content, book_tag): global START_PAGE for book_info in content: # 书名需要处理一下,split以空格分隔,移除空字符串,返回一个列表 f_title = book_info.select(\'.info h2\')[0].get_text().split() # 连接字符串 b_title = \'\'.join(f_title) pub_info= book_info.select(\'.info .pub\')[0].get_text().strip() desc_list = pub_info.split(\'/\') book_url = \'图书链接地址\' + book_info.select(\'.info h2 a\')[0].get(\'href\') pic_url = \'图片链接地址\' + book_info.select(\'.pic img\')[0].get(\'src\') try: author_info = \'作者/译者: \' + \'/\'.join(desc_list[0:-3]) except: author_info = \'作者/译者: 暂无\' try: pub_info = \'出版信息: \' + \'/\'.join(desc_list[-3:]) except: pub_info = \'出版信息: 暂无\' try: rating = book_info.select(\'.info .rating_nums\')[0].get_text().strip() except: rating = \'0.0\' try: # people_num = book_info.findAll(\'span\')[2].string.strip() people_num = book_info.select(\'.info .pl\')[0].get_text().strip() except: people_num = \'0\' # 以标签为文件名,保存起来 with open(\'%s.txt\' % book_tag,\'a\', encoding=\'utf8\') as f: f.write(\'%s %s %s %s %s %s %s\' % (b_title, rating, people_num, author_info, pub_info,book_url,pic_url)) f.write(\'\n\') # 打印出下载的页面 print(\'Downloading Information From Page %d\' % START_PAGE) # 页数加1 START_PAGE += 1 if __name__ == \'__main__\': START_PAGE = 1 book_tag_list = [] # 打印的标签名 printTag() while True: inp = input(\'请输入要抓取的标签名(q退出):\') if inp.lower() == \'q\': break book_tag_list.append(inp) # 页数: end = input(\'想抓取的页数:\') # 抓取每个标签底下的书籍 devideTag(book_tag_list)
结果:
[\'小说\', \'日本\', \'历史\', \'外国文学\', \'文学\', \'中国\', \'心理学\'] [\'漫画\', \'随笔\', \'哲学\', \'中国文学\', \'推理\', \'绘本\', \'美国\'] [\'经典\', \'爱情\', \'日本文学\', \'传记\', \'文化\', \'散文\', \'社会学\'] [\'青春\', \'英国\', \'旅行\', \'科普\', \'东野圭吾\', \'科幻\', \'生活\'] ......................................... [\'散文随笔\', \'国学\', \'时间管理\', \'当代文学\', \'日系推理\', \'心灵\', \'科幻小说\'] [\'法国文学\', \'温暖\', \'政治哲学\', \'科学\', \'英文原版\', \'灵修\', \'毛姆\'] [\'BL\'] 请输入要抓取的标签名(q退出):国学 请输入要抓取的标签名(q退出):轻小说 请输入要抓取的标签名(q退出):q 想抓取的页数:40 Downloading Information From Page 1 Downloading Information From Page 2 .............. Downloading Information From Page 39 Downloading Information From Page 40 Downloading Information From Page 1 Downloading Information From Page 2 .......................... Downloading Information From Page 39 Downloading Information From Page 40
写一个脚本,导入Django的数据库中:
#!/usr/bin/env python import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") def main(): from blog.models import Book f = open(\'轻小说.txt\') BookList = [] for line in f: title,author............ = line.split( ) book = Book(title=title,author=author..........) BookList.append(book) f.close() Blog.objects.bulk_create(BlogList) if __name__ == "__main__": main() print(\'Done!\')
遇到的问题:
1、最大的问题就是将数据写入本地文件中,出错:
使用Python写文件的时候,或者将网络数据流写入到本地文件的时候,大部分情况下会遇到:UnicodeEncodeError: \’gbk\’ codec can\’t encode character \’\xa0\’ in position … 这个问题。 网络上有很多类似的文件讲述如何解决这个问题,但是无非就是encode,decode相关的,这是导致该问题出现的真正原因吗?不是的。 很多时候,我们使用了decode和encode,试遍了各种编码,utf8,utf-8,gbk,gb2312等等,该有的编码都试遍了,可是编译的时候仍然出现: UnicodeEncodeError: \’gbk\’ codec can\’t encode character \’\xa0\’ in position XXX。 崩溃了。
在windows下面编写python脚本,编码问题很严重。
将网络数据流写入文件时时,我们会遇到几个编码:
1: #encoding=\’XXX\’ 这里(也就是python文件第一行的内容)的编码是指该python脚本文件本身的编码,无关紧要。只要XXX和文件本身的编码相同就行了。 比如notepad++ “格式”菜单里面里可以设置各种编码,这时需要保证该菜单里设置的编码和encoding XXX相同就行了,不同的话会报错
2:网络数据流的编码 比如获取网页,那么网络数据流的编码就是网页的编码。需要使用decode解码成unicode编码。
3:目标文件的编码 要将网络数据流的编码写入到新文件,那么我么需要指定新文件的编码。写文件代码如:
f.write(txt)
,那么txt是一个字符串,它是通过decode解码过的字符串。关键点就要来了:目标文件的编码是导致标题所指问题的罪魁祸首。如果我们打开一个文件:
f = open(“out.html”,”w”)
,在windows下面,新文件的默认编码是gbk,这样的话,python解释器会用gbk编码去解析我们的网络数据流txt,然而txt此时已经是decode过的unicode编码,这样的话就会导致解析不了,出现上述问题。 解决的办法就是,改变目标文件的编码:
f = open(“out.html”,”w”,encoding=\’utf-8\’)
。这样,问题将不复存在。
2、获取的标签列表很多,不能每个标签打印一次,独占一行。也不能一次都打出,这么多标签占一行:
有点像网页分页的问题,自己也是按照这种思路解决的,用切片的方式从列表中取出
tag_list = [] start = 0 end = 7 for tag in tags: tag_list.append(tag.get_text()) tr, td = divmod(len(tag_list), 7) # print(tr, td) if td != 0: tr = tr + 1 for i in range(tr): print(tag_list[start:end]) start, end = end, end + 7
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan