原創技術公眾號:
bigsai
,本文在1024釋出,祝大家節日快樂,心想事成。
@
前言
在本人上的一門課中,老師對每個小組有個任務要求,介紹和完成一個小模組、工具知識的使用。然而我所在的組剛好遇到的是python爬蟲的小課題。
心想這不是很簡單嘛,搞啥呢?想著去搞新的時間精力可能不太夠,索性自己就把豆瓣電影的評論(短評)搞一搞吧。
之前有寫過哪吒那篇類似的,但今天這篇要寫的像姨母般詳細。本篇主要實現的是對任意一部電影短評(熱門)的抓取以及視覺化分析。 也就是你只要提供連結和一些基本資訊,他就可以
分析
對於豆瓣爬蟲,what shold we 考慮?怎麼分析呢?豆瓣電影首頁
這個首先的話嘗試就可以啦,開啟任意一部電影,這裡以姜子牙為例。開啟姜子牙你就會發現它是非動態渲染的頁面,也就是傳統的渲染方式,直接請求這個url
即可獲取資料。但是翻著翻著頁面你就會發現:未登入使用者只能訪問優先的介面,登入的使用者才能有許可權去訪問後面的頁面。
所以這個流程應該是 登入——> 爬蟲——>儲存——>視覺化分析。
這裡提一下環境和所需要的安裝裝,環境為python3,程式碼在win和linux可成功跑,如果mac和linux不能跑友字型亂碼問題還請私我。其中pip用到包如下,直接用清華 映象下載不然很慢很慢(夠貼心不)。
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
登入
進去後有個密碼登入欄,我們要分析在登入的途中發生了啥,開啟F12控制檯是不夠的,我們還要使用Fidder抓包。
開啟F12控制檯然後點選登入,多次試探之後發現登入介面也很簡單:
檢視請求的引數發現就是普通請求,無加密,當然這裡可以用fidder進行抓包,這裡我簡單測試了一下用錯誤密碼進行測試。如果失敗的小夥伴可以嘗試手動登陸再退出這樣再跑程式。
這樣編寫登入模組的程式碼:
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
這塊高清之後,整個執行流程大概為:
爬取
成功登入之後,我們就可以攜帶登入的資訊訪問網站為所欲為的爬取資訊了。雖然它是傳統互動方式,但是每當你切換頁面時候會發現有個ajax請求。
這部分介面我們可以直接拿到評論部分的資料,就不需要請求整個頁面然後提取這部分的內容了。而這部分的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搜素分成若干小組進行曹祖就可以。
在具體的實現上,我們使用requests傳送請求獲取結果,使用BeautifulSoup去解析html格式檔案。
而我們所需要的資料也很容易分析對應部分。
實現的程式碼為:
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)
這個測試的執行結果為:
儲存
資料爬取完就要考慮儲存,我們將資料儲存到cvs中。
使用xlwt將資料寫入excel檔案中,xlwt基本應用例項:
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基本應用例項:
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))#輸出每一行
到這裡,我們對登入模組+爬取模組+儲存模組就可把資料存到本地了,具體整合的程式碼為:
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)
執行之後成功儲存資料:
視覺化分析
我們要對評分進行統計、詞頻統計。還有就是生成詞雲展示。而對應的就是matplotlib
、WordCloud
庫。
實現的邏輯思路:讀取xls的檔案,將評論使用分詞處理統計詞頻,統計出現最多的詞語製作成直方圖和詞語。將評星?數量做成餅圖展示一下,主要程式碼均有註釋,具體的程式碼為:
其中程式碼為:
import matplotlib.pyplot as plt
import matplotlib
import jieba
import jieba.analyse
import xlwt
import xlrd
from wordcloud import WordCloud
import numpy as np
from collections import Counter
# 設定字型 有的linux字型有問題
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
# 類似comment 為評論的一些資料 [ ['1','名稱','star星','贊同數','評論內容'] ,['2','名稱','star星','贊同數','評論內容'] ]元組
def anylasescore(comment):
score = [0, 0, 0, 0, 0, 0] # 分別對應0 1 2 3 4 5分出現的次數
count = 0 # 評分總次數
for va in comment: # 遍歷每條評論的資料 ['1','名稱','star星','贊同數','評論內容']
try:
score[int(va[2])] += 1 # 第3列 為star星 要強制轉換成int格式
count += 1
except Exception as e:
continue
print(score)
label = '1分', '2分', '3分', '4分', '5分'
color = 'blue', 'orange', 'yellow', 'green', 'red' # 各類別顏色
size = [0, 0, 0, 0, 0] # 一個百分比數字 合起來為100
explode = [0, 0, 0, 0, 0] # explode :(每一塊)離開中心距離;
for i in range(1, 5): # 計算
size[i] = score[i] * 100 / count
explode[i] = score[i] / count / 10
pie = plt.pie(size, colors=color, explode=explode, labels=label, shadow=True, autopct='%1.1f%%')
for font in pie[1]:
font.set_size(8)
for digit in pie[2]:
digit.set_size(8)
plt.axis('equal') # 該行程式碼使餅圖長寬相等
plt.title(u'各個評分佔比', fontsize=12) # 標題
plt.legend(loc=0, bbox_to_anchor=(0.82, 1)) # 圖例
# 設定legend的字型大小
leg = plt.gca().get_legend()
ltext = leg.get_texts()
plt.setp(ltext, fontsize=6)
plt.savefig("score.png")
# 顯示圖
plt.show()
def getzhifang(map): # 直方圖二維,需要x和y兩個座標
x = []
y = []
for k, v in map.most_common(15): # 獲取前15個最大數值
x.append(k)
y.append(v)
Xi = np.array(x) # 轉成numpy的座標
Yi = np.array(y)
width = 0.6
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標籤
plt.figure(figsize=(8, 6)) # 指定影像比例: 8:6
plt.bar(Xi, Yi, width, color='blue', label='熱門詞頻統計', alpha=0.8, )
plt.xlabel("詞頻")
plt.ylabel("次數")
plt.savefig('zhifang.png')
plt.show()
return
def getciyun_most(map): # 獲取詞雲
# 一個存對應中文單詞,一個存對應次數
x = []
y = []
for k, v in map.most_common(300): # 在前300個常用詞語中
x.append(k)
y.append(v)
xi = x[0:150] # 擷取前150個
xi = ' '.join(xi) # 以空格 ` `將其分割為固定格式(詞雲需要)
print(xi)
# backgroud_Image = plt.imread('') # 如果需要個性化詞雲
# 詞雲大小,字型等基本設定
wc = WordCloud(background_color="white",
width=1500, height=1200,
# min_font_size=40,
# mask=backgroud_Image,
font_path="simhei.ttf",
max_font_size=150, # 設定字型最大值
random_state=50, # 設定有多少種隨機生成狀態,即有多少種配色方案
) # 字型這裡有個坑,一定要設這個引數。否則會顯示一堆小方框wc.font_path="simhei.ttf" # 黑體
# wc.font_path="simhei.ttf"
my_wordcloud = wc.generate(xi) #需要放入詞雲的單詞 ,這裡前150個單詞
plt.imshow(my_wordcloud) # 展示
my_wordcloud.to_file("img.jpg") # 儲存
xi = ' '.join(x[150:300]) # 再次獲取後150個單詞再儲存一張詞雲
my_wordcloud = wc.generate(xi)
my_wordcloud.to_file("img2.jpg")
plt.axis("off")
def anylaseword(comment):
# 這個過濾詞,有些詞語沒意義需要過濾掉
list = ['這個', '一個', '不少', '起來', '沒有', '就是', '不是', '那個', '還是', '劇情', '這樣', '那樣', '這種', '那種', '故事', '人物', '什麼']
print(list)
commnetstr = '' # 評論的字串
c = Counter() # python一種資料集合,用來儲存字典
index = 0
for va in comment:
seg_list = jieba.cut(va[4], cut_all=False) ## jieba分詞
index += 1
for x in seg_list:
if len(x) > 1 and x != '\r\n': # 不是單個字 並且不是特殊符號
try:
c[x] += 1 # 這個單詞的次數加一
except:
continue
commnetstr += va[4]
for (k, v) in c.most_common(): # 過濾掉次數小於5的單詞
if v < 5 or k in list:
c.pop(k)
continue
# print(k,v)
print(len(c), c)
getzhifang(c) # 用這個資料進行畫直方圖
getciyun_most(c) # 詞雲
# print(commnetstr)
def anylase():
data = xlrd.open_workbook('test.xls') # 開啟xls檔案
table = data.sheets()[0] # 開啟第i張表
nrows = table.nrows # 若干列的一個集合
comment = []
for i in range(nrows):
comment.append(table.row_values(i)) # 將該列資料新增到元組中
# print(comment)
anylasescore(comment)
anylaseword(comment)
if __name__ == '__main__':
anylase()
我們再來檢視一下執行的效果:
這裡我選了姜子牙和千與千尋 電影的一些資料,兩個電影評分比例對比為:
從評分可以看出明顯千與千尋好評度更高,大部分人願意給他五分。基本算是最好看的動漫之一了,再來看看直方圖的詞譜:
很明顯千與千尋的作者更出名,並且有很大的影響力,以至於大家紛紛提起他。再看看兩者詞雲圖:
宮崎駿、白龍、婆婆,真的是滿滿的回憶,好了不說了,有啥想說的歡迎討論!
如果感覺不錯,點贊、一鍵三連 原創公眾號:bigsai,分享知識和乾貨!