繼上一篇【Python數據分析】Python3操作Excel-以豆瓣圖書Top250為例 對豆瓣圖書Top250進行爬取以後,鑒於還有一些問題沒有解決,所以進行了進一步的交流討論,這期間得到了一隻尼瑪的幫助與啟發,十分感謝! 上次存在的問題如下: 1.寫入不能繼續的問題 2.在Python IDLE ...
繼上一篇【Python數據分析】Python3操作Excel-以豆瓣圖書Top250為例 對豆瓣圖書Top250進行爬取以後,鑒於還有一些問題沒有解決,所以進行了進一步的交流討論,這期間得到了一隻尼瑪的幫助與啟發,十分感謝!
上次存在的問題如下:
1.寫入不能繼續的問題
2.在Python IDLE中明明輸出正確的結果,寫到excel中就亂碼了。
上述兩個問題促使我改換excel處理模塊,因為據說xlwt只支持到Excel 2003,很有可能會出問題。
雖然“一隻尼瑪”給了一個Validate函數,可是那是針對去除Windows下文件名中非法字元的函數,跟寫入excel亂碼沒有關係,所以還是考慮更換模塊。
更換xlsxwriter模塊
這次我改成xlsxwriter這個模塊,https://pypi.python.org/pypi/XlsxWriter. 同樣可以pip3 install xlsxwriter,自動下載安裝,簡便易行。一些用法樣例:
import xlsxwriter # Create an new Excel file and add a worksheet. workbook = xlsxwriter.Workbook('demo.xlsx') worksheet = workbook.add_worksheet() # Widen the first column to make the text clearer. worksheet.set_column('A:A', 20) # Add a bold format to use to highlight cells. bold = workbook.add_format({'bold': True}) # Write some simple text. worksheet.write('A1', 'Hello') # Text with formatting. worksheet.write('A2', 'World', bold) # Write some numbers, with row/column notation. worksheet.write(2, 0, 123) worksheet.write(3, 0, 123.456) # Insert an image. worksheet.insert_image('B5', 'logo.png') workbook.close()
果斷更換寫入excel的代碼。效果如下:
果然鼻子是鼻子臉是臉,該是鏈接就是鏈接,不管什麼字元都能寫,畢竟unicode。
所以說,選對模塊很重要!選對模塊很重要!選對模塊很重要!(重說三)
如果要爬的內容不是很公正標準的字元串或數字的話,我是不會用xlwt啦。
這裡有4中Python寫入excel的模塊對比:http://ju.outofmemory.cn/entry/56671
我截了一個對比圖如下,具體可以看上面那篇文章,非常詳細!
順藤摸瓜
這個既然如此順暢,還可以寫入圖片,那我們何不試試看呢?
目標:把圖片鏈接那一列的內容換成真正的圖片!
其實很簡單,因為我們之前已經有了圖片的存儲路徑,把它插入到裡面就可以了。
the_img = "I:\\douban\\image\\"+bookName+".jpg" writelist=[i+j,bookName,nickname,rating,nums,the_img,bookurl,notion,tag] for k in range(0,9): if k == 5: worksheet.insert_image(i+j,k,the_img) else: worksheet.write(i+j,k,writelist[k])
出來是這樣的效果,顯然不美觀,那我們應該適當調整一些每行的高度,以及讓他們居中試試看:
查閱xlsxwriter文檔可知,可以這麼設置行列寬度和居中:(當然,這些操作在excel中可以直接做,而且可能會比寫代碼更快,但是我倒是想更多試試這個模塊)
format = workbookx.add_format() format.set_align('justify') format.set_align('center') format.set_align('vjustify') format.set_align('vcenter') format.set_text_wrap() worksheet.set_row(0,12,format) for i in range(1,251): worksheet.set_row(i,70) worksheet.set_column('A:A',3,format) worksheet.set_column('B:C',17,format) worksheet.set_column('D:D',4,format) worksheet.set_column('E:E',7,format) worksheet.set_column('F:F',10,format) worksheet.set_column('G:G',19,format) worksheet.set_column('H:I',40,format)
至此完成了excel的寫入,只不過設置格式這塊實在繁雜,得不斷調試距離,大小,所以在excel裡面做會簡單些。
最終代碼:
# -*- coding:utf-8 -*- import requests import re import xlwt import xlsxwriter from bs4 import BeautifulSoup from datetime import datetime import codecs now = datetime.now() #開始計時 print(now) def validate(title): #from nima rstr = r"[\/\\\:\*\?\"\<\>\|]" # '/\:*?"<>|-' new_title = re.sub(rstr, "", title) return new_title txtfile = codecs.open("top2501.txt",'w','utf-8') url = "http://book.douban.com/top250?" header = { "User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.13 Safari/537.36", "Referer": "http://book.douban.com/" } image_dir = "I:\\douban\\image\\" #下載圖片 def download_img(imageurl,imageName = "xxx.jpg"): rsp = requests.get(imageurl, stream=True) image = rsp.content path = image_dir + imageName +'.jpg' #print(path) with open(path,'wb') as file: file.write(image) #建立Excel workbookx = xlsxwriter.Workbook('I:\\douban\\btop250.xlsx') worksheet = workbookx.add_worksheet() format = workbookx.add_format() format.set_align('justify') format.set_align('center') format.set_align('vjustify') format.set_align('vcenter') format.set_text_wrap() worksheet.set_row(0,12,format) for i in range(1,251): worksheet.set_row(i,70) worksheet.set_column('A:A',3,format) worksheet.set_column('B:C',17,format) worksheet.set_column('D:D',4,format) worksheet.set_column('E:E',7,format) worksheet.set_column('F:F',10,format) worksheet.set_column('G:G',19,format) worksheet.set_column('H:I',40,format) item = ['書名','別稱','評分','評價人數','封面','圖書鏈接','出版信息','標簽'] for i in range(1,9): worksheet.write(0,i,item[i-1]) s = requests.Session() #建立會話 s.get(url,headers=header) for i in range(0,250,25): geturl = url + "/start=" + str(i) #要獲取的頁面地址 print("Now to get " + geturl) postData = {"start":i} #post數據 res = s.post(url,data = postData,headers = header) #post soup = BeautifulSoup(res.content.decode(),"html.parser") #BeautifulSoup解析 table = soup.findAll('table',{"width":"100%"}) #找到所有圖書信息的table sz = len(table) #sz = 25,每頁列出25篇文章 for j in range(1,sz+1): #j = 1~25 sp = BeautifulSoup(str(table[j-1]),"html.parser") #解析每本圖書的信息 imageurl = sp.img['src'] #找圖片鏈接 bookurl = sp.a['href'] #找圖書鏈接 bookName = sp.div.a['title'] nickname = sp.div.span #找別名 if(nickname): #如果有別名則存儲別名否則存’無‘ nickname = nickname.string.strip() else: nickname = "" notion = str(sp.find('p',{"class":"pl"}).string) #抓取出版信息,註意裡面的.string還不是真的str類型 rating = str(sp.find('span',{"class":"rating_nums"}).string) #抓取平分數據 nums = sp.find('span',{"class":"pl"}).string #抓取評分人數 nums = nums.replace('(','').replace(')','').replace('\n','').strip() nums = re.findall('(\d+)人評價',nums)[0] download_img(imageurl,bookName) #下載圖片 book = requests.get(bookurl) #打開該圖書的網頁 sp3 = BeautifulSoup(book.content,"html.parser") #解析 taglist = sp3.find_all('a',{"class":" tag"}) #找標簽信息 tag = "" lis = [] for tagurl in taglist: sp4 = BeautifulSoup(str(tagurl),"html.parser") #解析每個標簽 lis.append(str(sp4.a.string)) tag = ','.join(lis) #加逗號 the_img = "I:\\douban\\image\\"+bookName+".jpg" writelist=[i+j,bookName,nickname,rating,nums,the_img,bookurl,notion,tag] for k in range(0,9): if k == 5: worksheet.insert_image(i+j,k,the_img) else: worksheet.write(i+j,k,writelist[k]) txtfile.write(str(writelist[k])) txtfile.write('\t') txtfile.write(u'\r\n') end = datetime.now() #結束計時 print(end) print("程式耗時: " + str(end-now)) txtfile.close() workbookx.close()View Code
運行結果如下:
2016-03-28 11:40:50.525635 Now to get http://book.douban.com/top250?/start=0 Now to get http://book.douban.com/top250?/start=25 Now to get http://book.douban.com/top250?/start=50 Now to get http://book.douban.com/top250?/start=75 Now to get http://book.douban.com/top250?/start=100 Now to get http://book.douban.com/top250?/start=125 Now to get http://book.douban.com/top250?/start=150 Now to get http://book.douban.com/top250?/start=175 Now to get http://book.douban.com/top250?/start=200 Now to get http://book.douban.com/top250?/start=225 2016-03-28 11:48:14.946184 程式耗時: 0:07:24.420549
順利爬完250本書。此次爬取行動就正確性來說已告完成!
本次耗時7分24秒,還是顯得太慢了。下一步就應該是如何在提高效率上面下功夫了。