1. 程式人生 > >用python寫一個豆瓣短評通用爬蟲(登入、爬取、視覺化)

用python寫一個豆瓣短評通用爬蟲(登入、爬取、視覺化)

>原創技術公眾號:`bigsai`,本文在1024釋出,祝大家節日快樂,心想事成。 @[TOC](文章結構) ## 前言 在本人上的一門課中,老師對每個小組有個任務要求,介紹和完成一個小模組、工具知識的使用。然而我所在的組剛好遇到的是python爬蟲的小課題。 心想這不是很簡單嘛,搞啥呢?想著去搞新的時間精力可能不太夠,索性自己就把豆瓣電影的評論(短評)搞一搞吧。 之前有寫過哪吒那篇類似的,但今天這篇要寫的像姨母般詳細。**本篇主要實現的是對任意一部電影短評(熱門)的抓取以及視覺化分析。** 也就是你只要提供連結和一些基本資訊,他就可以 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201016104115813.png) **分析** 對於豆瓣爬蟲,what shold we 考慮?怎麼分析呢?[豆瓣電影首頁](https://movie.douban.com/) 這個首先的話嘗試就可以啦,開啟任意一部電影,這裡以**姜子牙**為例。開啟姜子牙你就會發現它是非動態渲染的頁面,也就是傳統的渲染方式,直接請求這個`url`即可獲取資料。但是翻著翻著頁面你就會發現:未登入使用者只能訪問優先的介面,登入的使用者才能有許可權去訪問後面的頁面。 ![image-20201022195020410](https://img-blog.csdnimg.cn/img_convert/45738c3057a9006a56662cb969a888ef.png) 所以這個流程應該是 **登入——> 爬蟲——>儲存——>視覺化分析**。 這裡提一下環境和所需要的安裝裝,環境為python3,程式碼在win和linux可成功跑,如果mac和linux不能跑友字型亂碼問題還請私我。其中pip用到包如下,直接用清華 映象下載不然很慢很慢(夠貼心不)。 ```python pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple pip install xlrd -i https://pypi.tuna.tsinghua.edu.cn/simple pip install xlwt -i https://pypi.tuna.tsinghua.edu.cn/simple pip install bs4 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simple pip install wordcloud -i https://pypi.tuna.tsinghua.edu.cn/simple pip install jieba -i https://pypi.tuna.tsinghua.edu.cn/simple ``` ## 登入 [豆瓣的登入地址](https://accounts.douban.com/passport/login?source=movie) 進去後有個密碼登入欄,我們要分析在登入的途中發生了啥,開啟F12控制檯是不夠的,我們還要使用Fidder抓包。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201016153829779.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNjkzMTcx,size_1,color_FFFFFF,t_70) 開啟F12控制檯然後點選登入,多次試探之後發現登入介面也很簡單: ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201016155054170.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNjkzMTcx,size_1,color_FFFFFF,t_70) 檢視請求的引數發現就是普通請求,**無加密**,當然這裡可以用fidder進行抓包,這裡我簡單測試了一下用錯誤密碼進行測試。如果失敗的小夥伴可以嘗試手動登陸再退出這樣再跑程式。 ![image-20201022195625220](https://img-blog.csdnimg.cn/img_convert/7cb143d8600e1514a576cf773a958ec0.png) 這樣編寫登入模組的程式碼: ```python url='https://accounts.douban.com/j/mobile/login/basic' header={'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36', 'Referer': 'https://accounts.douban.com/passport/login_popup?login_source=anony', 'Origin': 'https://accounts.douban.com', 'content-Type':'application/x-www-form-urlencoded', 'x-requested-with':'XMLHttpRequest', 'accept':'application/json', 'accept-encoding':'gzip, deflate, br', 'accept-language':'zh-CN,zh;q=0.9', 'connection': 'keep-alive' ,'Host': 'accounts.douban.com' } data={ 'ck':'', 'name':'', 'password':'', 'remember':'false', 'ticket':'' } def login(username,password): global data data['name']=username data['password']=password data=urllib.parse.urlencode(data) print(data) req=requests.post(url,headers=header,data=data,verify=False) cookies = requests.utils.dict_from_cookiejar(req.cookies) print(cookies) return cookies ``` 這塊高清之後,整個執行流程大概為: ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201016161024925.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNjkzMTcx,size_1,color_FFFFFF,t_70) ## 爬取 成功登入之後,我們就可以攜帶登入的資訊訪問網站為所欲為的爬取資訊了。雖然它是傳統互動方式,但是每當你切換頁面時候會發現有個ajax請求。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201016162136796.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNjkzMTcx,size_1,color_FFFFFF,t_70) 這部分介面我們可以直接拿到評論部分的資料,就不需要請求整個頁面然後提取這部分的內容了。而這部分的url規律和之前分析的也是一樣,只有一個`start`表示當前的條數在變化,所以直接拼湊url就行。 也就是用邏輯拼湊url一直到不能正確操作為止。 ``` https://movie.douban.com/subject/25907124/comments?percent_type=&start=0&其他引數省略 https://movie.douban.com/subject/25907124/comments?percent_type=&start=20&其他引數省略 https://movie.douban.com/subject/25907124/comments?percent_type=&start=40&其他引數省略 ``` 對於每個url訪問之後如何提取資訊呢? 我們根據css選擇器進行篩選資料,因為每個評論他們的樣式相同,在html中就很像一個列表中的元素一樣。 再觀察我們剛剛那個ajax介面返回的資料剛好是下面紅色區域塊,所以我們直接根據class搜素分成若干小組進行曹祖就可以。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201016164150576.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNjkzMTcx,size_16,color_FFFFFF,t_70#pic_center) 在具體的實現上,我們使用requests傳送請求獲取結果,使用BeautifulSoup去解析html格式檔案。 而我們所需要的資料也很容易分析對應部分。 ![image-20201022210917778](https://img-blog.csdnimg.cn/img_convert/666f0cbf5f76a37847713ba47b7d87b1.png) 實現的程式碼為: ```python import requests from bs4 import BeautifulSoup url='https://movie.douban.com/subject/25907124/comments?percent_type=&start=0&limit=20&status=P&sort=new_score&comments_only=1&ck=C7di' header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36', } req = requests.get(url,headers=header,verify=False) res = req.json() # 返回的結果是一個json res = res['html'] soup = BeautifulSoup(res, 'lxml') node = soup.select('.comment-item') for va in node: name = va.a.get('title') star = va.select_one('.comment-info').select('span')[1].get('class')[0][-2] comment = va.select_one('.short').text votes=va.select_one('.votes').text print(name, star,votes, comment) ``` 這個測試的執行結果為: ![image-20201022220333519](https://img-blog.csdnimg.cn/img_convert/1f25cd6df837ea2d430aef6298400900.png) ## 儲存 資料爬取完就要考慮儲存,我們將資料儲存到cvs中。 使用**xlwt**將資料寫入excel檔案中,xlwt基本應用例項: ```python import xlwt #建立可寫的workbook物件 workbook = xlwt.Workbook(encoding='utf-8') #建立工作表sheet worksheet = workbook.add_sheet('sheet1') #往表中寫內容,第一個引數 行,第二個引數列,第三個引數內容 worksheet.write(0, 0, 'bigsai') #儲存表為test.xlsx workbook.save('test.xlsx') ``` 使用**xlrd**讀取excel檔案中,本案例xlrd基本應用例項: ```python import xlrd #讀取名稱為test.xls檔案 workbook = xlrd.open_workbook('test.xls') # 獲取第一張表 table = workbook.sheets()[0] # 開啟第1張表 # 每一行是個元組 nrows = table.nrows for i in range(nrows): print(table.row_values(i))#輸出每一行 ``` 到這裡,我們對登入模組+爬取模組+儲存模組就可把資料存到本地了,具體整合的程式碼為: ```python import requests from bs4 import BeautifulSoup import urllib.parse import xlwt import xlrd # 賬號密碼 def login(username, password): url = 'https://accounts.douban.com/j/mobile/login/basic' header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36', 'Referer': 'https://accounts.douban.com/passport/login_popup?login_source=anony', 'Origin': 'https://accounts.douban.com', 'content-Type': 'application/x-www-form-urlencoded', 'x-requested-with': 'XMLHttpRequest', 'accept': 'application/json', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9', 'connection': 'keep-alive' , 'Host': 'accounts.douban.com' } # 登陸需要攜帶的引數 data = { 'ck' : '', 'name': '', 'password': '', 'remember': 'false', 'ticket': '' } data['name'] = username data['password'] = password data = urllib.parse.urlencode(data) print(data) req = requests.post(url, headers=header, data=data, verify=False) cookies = requests.utils.dict_from_cookiejar(req.cookies) print(cookies) return cookies def getcomment(cookies, mvid): # 引數為登入成功的cookies(後臺可通過cookies識別使用者,電影的id) start = 0 w = xlwt.Workbook(encoding='ascii') # #建立可寫的workbook物件 ws = w.add_sheet('sheet1') # 建立工作表sheet index = 1 # 表示行的意思,在xls檔案中寫入對應的行數 while True: # 模擬瀏覽器頭髮送請求 header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36', } # try catch 嘗試,一旦有錯誤說明執行完成,沒錯誤繼續進行 try: # 拼湊url 每次star加20 url = 'https://movie.douban.com/subject/' + str(mvid) + '/comments?start=' + str( start) + '&limit=20&sort=new_score&status=P&comments_only=1' start += 20 # 傳送請求 req = requests.get(url, cookies=cookies, headers=header) # 返回的結果是個json字串 通過req.json()方法獲取資料 res = req.json() res = res['html'] # 需要的資料在`html`鍵下 soup = BeautifulSoup(res, 'lxml') # 把這個結構化html建立一個BeautifulSoup物件用來提取資訊 node = soup.select('.comment-item') # 每組class 均為comment-item 這樣分成20條記錄(每個url有20個評論) for va in node: # 遍歷評論 name = va.a.get('title') # 獲取評論者名稱 star = va.select_one('.comment-info').select('span')[1].get('class')[0][-2] # 星數好評 votes = va.select_one('.votes').text # 投票數 comment = va.select_one('.short').text # 評論文字 print(name, star, votes, comment) ws.write(index, 0, index) # 第index行,第0列寫入 index ws.write(index, 1, name) # 第index行,第1列寫入 評論者 ws.write(index, 2, star) # 第index行,第2列寫入 評星 ws.write(index, 3, votes) # 第index行,第3列寫入 投票數 ws.write(index, 4, comment) # 第index行,第4列寫入 評論內容 index += 1 except Exception as e: # 有異常退出 print(e) break w.save('test.xls') # 儲存為test.xls檔案 if __name__ == '__main__': username = input('輸入賬號:') password = input('輸入密碼:') cookies = login(username, password) mvid = input('電影的id為:') getcomment(cookies, mvid) ``` 執行之後成功儲存資料: ![image-20201022221256503](https://img-blog.csdnimg.cn/img_convert/563185e27f48fe483926c3d5511af95e.png) ## 視覺化分析 我們要對評分進行統計、詞頻統計。還有就是生成詞雲展示。而對應的就是`matplotlib`、`WordCloud`庫。 實現的邏輯思路:讀取xls的檔案,將評論使用分詞處理統計詞頻,統計出現最多的詞語製作成直方圖和詞語。將評星