宣告:本博客只是簡單的爬蟲示范,并不涉及任何商業用途,
一.前言
前段時間春節,博主有幸去電影院看了熱映的幾部電影,但是我想了解下大多數人對電影的看法,于是我便想到了爬蟲,由于之前爬過豆瓣和知乎,這次我將爬蟲物件改為了貓眼電影,我針對貓眼上的近期熱映電影的評論等資料進行了爬取,并將結果進行了簡單的可視化,下面是對本次爬蟲程序的記錄,希望能給大家有所啟迪,
二.網頁分析
首先我在電腦端打開貓眼官網,結果發現在其上面并沒有影評資料,通過查詢其他大佬的文章,我發現了貓眼電影的評論介面(參考于文章爬蟲實戰:貓眼《流浪地球》影評資料爬取和分析):
https://m.maoyan.com/movie/movie_id/comments?_v_=yes
其中movie_id為待爬取的電影的id,可以在貓眼官網首頁獲取,例如《人潮洶涌》的id為1300936,即《人潮洶涌》影評資料的介面為:
https://m.maoyan.com/movie/1300936/comments?_v_=yes
在瀏覽器中貼入該鏈接可以看到如下界面:

點擊F12鍵,不斷進行下拉可以看到評論資料所在的json如圖:

復制一個json資料連接下來如下:
https://m.maoyan.com/review/v2/comments.json?movieId=1300936&userId=-1&offset=15&limit=15&ts=1614503804212&type=3&optimus_uuid=CDD8C6B0775A11EB869539E04D007BD066D8CA91D8354B5C9BE678701804B84C&optimus_risk_level=71&optimus_code=10
多觀測幾個鏈接發現只有ts、offset等欄位發生變化,對于ts欄位,我通過時間戳在線轉換工具得到如下結果:

從轉換結果來看顯然是有問題的,但我發現將該數字除以1000再進行轉換發現結果正確,如圖:

而對于offset欄位可以明顯看出其值每翻一頁增加15,
三.爬蟲具體程序
基于以上分析即可以確定爬蟲的核心思路:先去貓眼主頁獲取熱映電影的id,然后通過上述發現的欄位變換規律去構造相應的鏈接即可獲取對應的評論的json資料,
爬蟲庫的選擇:requests,BeautifulSoup;
3.1 獲取熱映電影ID
首先打開貓眼電影主頁,選中一部熱映電影右鍵檢查,可以看到電影id和電影名所在的位置如下圖所示:

通過BeautifulSoup我們即可過濾出這些欄位出來,詳情參見get_hit_movieid.py,這里不做詳細介紹,
3.2 構造鏈接
有了上述的規律,電影評論的json資料的獲取其實很簡單了,示例如下:
# movieId為待爬取的電影ID
# i為爬蟲的頁數,從0開始
# ts為獲取的時間戳需要乘以1000
ts = time.time()
url = 'https://m.maoyan.com/review/v2/comments.json?movieId={}&userId=-1&offset={}&limit=15&ts={}&type=3&optimus_uuid=CDD8C6B0775A11EB869539E04D007BD066D8CA91D8354B5C9BE678701804B84C&optimus_risk_level=71&optimus_code=10'.format(self.movieId,i*15,int(ts*1000))
3.3 影評資料提取
通過構造的鏈接我們可以獲取包含影評資料的json檔案,然后利用json模塊進行加載,然后便可以輕易獲取自己想要的欄位,
3.4 爬蟲的優化措施
在爬蟲的程序中具體采用的優化措施如下:
- 利用fake_useragent來獲取不同的UserAgent,傳入獲取json資料那里對應的cookie;
- 為了加快爬蟲速度,這里采用了多執行緒方式(通過threading模塊實作),這里將每部熱映電影分配一個執行緒進行影評資料爬蟲;
3.5 資料的保存
影評資料通過Pandas模塊保存為csv檔案,其中包含5列資料分別為:
- id:用戶id;
- content:評論內容;
- nick:昵稱;
- score:用戶電影打分;
- startTime:評論時間;
3.6 注意事項
由于貓眼的反扒措施,好像每部電影最多一次只能爬取1000條左右的評論資料,但是在不同時間段內可以爬到不同的影評資料,因此可以通過該種方式來獲取更多的影評資料,
四.爬蟲部分代碼及可視化展示
4.1 爬蟲主程式代碼
import json
import time
import random
import requests
import traceback
import pandas as pd
from fake_useragent import UserAgent
from get_hit_movieid import getMovies,headers
from proxy_ip import ExtractIP
import threading
ua = UserAgent()
class MaoYanSpider(threading.Thread):
def __init__(self,movie_name,movieId,nums,threadname,IPs=None,append=False) -> None:
threading.Thread.__init__(self, name=threadname)
self.movieId = movieId
self.nums = nums
self.movie_name = movie_name
self.IPs = IPs
self.append = append
def run(self):
"""
爬蟲主程式
self.movieId:待爬取電影的id
self.nums:待爬取的頁數
self.IPs:代理IP串列
"""
clist = []
t = self.nums // 15
for i in range(nums):
try:
print('{} is clawling the {}st page'.format(self.getName(),i + 1))
ts = time.time()
url = 'https://m.maoyan.com/review/v2/comments.json?movieId={}&userId=-1&offset={}&limit=15&ts={}&type=3&optimus_uuid=CDD8C6B0775A11EB869539E04D007BD066D8CA91D8354B5C9BE678701804B84C&optimus_risk_level=71&optimus_code=10'\
.format(self.movieId,i*15,int(ts*1000))
# print(url)
# 設定代理IP
if self.IPs is not None:
index = random.randint(0,len(self.IPs) - 1)
proxies = {"http":"{}:8080".format(self.self.IPs[index])}
response = requests.get(url=url,headers=headers,proxies=proxies)
else:
proxies = {"http":"{}:8080".format('41.207.251.198')}
response = requests.get(url=url,headers=headers,proxies=proxies)
# with open('temp.html','w',encoding='utf-8') as fp:
# fp.write(response.text)
outcome = self.phrase(response.text)
# 爬取空串列則停止(貓眼爬蟲有條數限制)
if outcome == []:break
clist += outcome
time.sleep(1.5)
except Exception:
traceback.print_exc()
pass
self.Saver(clist,self.append)
def phrase(self,data):
"""
決議獲取的影評資料(json格式)
data:文本資料
"""
outcome = []
js_data = json.loads(data)
comments = js_data.get('data').get('comments')
if comments != None:
for comment in comments:
id = comment.get('id') # 電影ID
content = comment.get('content') # 評論的內容
nick = comment.get('nick') # 評論人的昵稱
score = comment.get('score') # 評論的分數
startTime = comment.get('startTime') # 開始時間
print(id,content,nick,score,startTime)
outcome.append([id,content,nick,score,startTime])
return outcome
def Saver(self,clist,append=False):
"""
功能:保存評論為csv檔案
clist:獲取的資料
append:是否為追加檔案到原有的檔案中去
"""
datas = pd.DataFrame(clist,columns=['id','content','nick','score','startTime'])
if append:
datas.to_csv('datas/{}.csv'.format(self.movie_name),index=False,header=False,mode='a')
else:
datas.to_csv('datas/{}.csv'.format(self.movie_name),index=False)
if __name__ == "__main__":
movies = getMovies()
IPs = ExtractIP()
IPs = None if IPs == [] else IPs
i = 1
for k,v in movies.items():
movie_name = k
movieId,nums = v[0],v[1]
print(movie_name,'\t',movieId,'\t',nums)
threadname = 'spider{}'.format(i)
spider = MaoYanSpider(movie_name,movieId,nums,threadname,IPs,append=True).start()
i += 1
4.2 影評資料可視化
4.2.1 電影評分情況圓環圖
對于電影的評分情況也是通過Pandas模塊來進行獲取,具體通過groupby函式來按評分等級進行分組然后統計,最后將0~5分的總結在了一起,代碼如下所示:
def scoreDistribution(df):
"""
獲取評分及評分人數
df:dataframe形式資料
"""
mdata = df[['score','id']].groupby('score').count()
score_nums = mdata['id'].tolist()[6:]
labels = mdata.index.tolist()[6:]
# 合并5分以下的
score_nums.insert(0,mdata.loc[0:5,:].sum().values.item())
labels.insert(0,'0~5')
return score_nums,labels
然后通過Matplotlib模塊的pie函式來進行了8部熱映電影的圓環圖的繪制,下面挑選《人潮洶涌》的圖來進行展示:

4.2.2 評論資料詞云圖
對于詞云圖的繪制,先需要利用jieba分詞來對影評內容進行分詞,然后利用wordcloud模塊來進行詞云圖的繪制,這里同樣展示《人潮洶涌》的詞云:

從上述資料可以看出大多數人都人潮洶涌打分頗高,認為這是一部值得觀看的電影,同樣作為一名觀影者,我也持有同樣的看法,
五.結語
完整專案Github地址(求star):maoyan_movie_commit
由于獲取的資料不多,因此上述的結果并不具有權威性,僅僅是作者的自娛自樂,以上便是本文的全部內容,要是覺得不錯的話就點個贊或關注一下博主吧,你們的支持是博主繼續創作的不解動力,當然若是有任何問題也敬請批評指正!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/264843.html
標籤:python
