Python采集貓眼兩萬條數(shù)據(jù) 對《無名之輩》影評進行分析
一、說明
本文主要講述采集貓眼電影用戶評論進行分析,相關(guān)爬蟲采集程序可以爬取多個電影評論。
運行環(huán)境:Win10/Python3.5。
分析工具:jieba、wordcloud、pyecharts、matplotlib。
基本流程:下載內(nèi)容 ---> 分析獲取關(guān)鍵數(shù)據(jù) ---> 保存本地文件 ---> 分析本地文件制作圖表
注意:本文所有圖文和源碼僅供學(xué)習(xí),請勿他用,轉(zhuǎn)發(fā)請注明出處!
本文主要參考:https://mp.weixin.qq.com/s/mTxxkwRZPgBiKC3Sv-jo3g
二、開始采集
2.1、分析數(shù)據(jù)接口:
為了健全數(shù)據(jù)樣本,數(shù)據(jù)直接從移動端接口進行采集,連接如下,其中橙色部分為貓眼電影ID,修改即可爬取其他電影。
鏈接地址:http://m.maoyan.com/mmdb/comments/movie/1208282.json?v=yes&offset=15&startTime=

接口返回的數(shù)據(jù)如下,主要采集(昵稱、城市、評論、評分和時間),用戶評論在 json['cmts'] 中:

2.2、爬蟲程序核心內(nèi)容(詳細可以看后面源代碼):
>啟動腳本需要的參數(shù)如下(腳本名+貓眼電影ID+上映日期+數(shù)據(jù)保存的文件名):.\myMovieComment.py 1208282 2016-11-16 myCmts2.txt
>下載html內(nèi)容:download(self, url),通過python的requests模塊進行下載,將下載的數(shù)據(jù)轉(zhuǎn)成json格式
def download(self, url):
"""下載html內(nèi)容"""
print("正在下載URL: "+url)
# 下載html內(nèi)容
response = requests.get(url, headers=self.headers)
# 轉(zhuǎn)成json格式數(shù)據(jù)
if response.status_code == 200:
return response.json()
else:
# print(html.status_code)
print('下載數(shù)據(jù)為空!')
return ""
>然后就是對已下載的內(nèi)容進行分析,就是取出我們需要的數(shù)據(jù):
def parse(self, content):
"""分析數(shù)據(jù)"""
comments = []
try:
for item in content['cmts']:
comment = {
'nickName': item['nickName'], # 昵稱
'cityName': item['cityName'], # 城市
'content': item['content'], # 評論內(nèi)容
'score': item['score'], # 評分
'startTime': item['startTime'], # 時間
}
comments.append(comment)
except Exception as e:
print(e)
finally:
return comments
>將分析出來的數(shù)據(jù),進行本地保存,方便后續(xù)的分析工作:
def save(self, data):
"""寫入文件"""
print("保存數(shù)據(jù),寫入文件中...")
self.save_file.write(data)
> 爬蟲的核心控制也即爬蟲的程序啟動入口,管理上面幾個方法的有序執(zhí)行:
def start(self):
"""啟動控制方法"""
print("爬蟲開始...\r\n")
start_time = self.start_time
end_time = self.end_time
num = 1
while start_time > end_time:
print("執(zhí)行次數(shù):", num)
# 1、下載html
content = self.download(self.target_url + str(start_time))
# 2、分析獲取關(guān)鍵數(shù)據(jù)
comments = ''
if content != "":
comments = self.parse(content)
if len(comments) <= 0:
print("本次數(shù)據(jù)量為:0,退出爬?。r\n")
break
# 3、寫入文件
res = ''
for cmt in comments:
res += "%s###%s###%s###%s###%s\n" % (cmt['nickName'], cmt['cityName'], cmt['content'], cmt['score'], cmt['startTime'])
self.save(res)
print("本次數(shù)據(jù)量:%s\r\n" % len(comments))
# 獲取最后一條數(shù)據(jù)的時間 ,然后減去一秒
start_time = datetime.strptime(comments[len(comments) - 1]['startTime'], "%Y-%m-%d %H:%M:%S") + timedelta(seconds=-1)
# start_time = datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S")
# 休眠3s
num += 1
time.sleep(3)
self.save_file.close()
print("爬蟲結(jié)束...")
2.3 數(shù)據(jù)樣本,最終爬取將近2萬條數(shù)據(jù),每條記錄的每個數(shù)據(jù)使用 ### 進行分割:

三、圖形化分析數(shù)據(jù)
3.1、制作觀眾城市分布熱點圖,(pyecharts-geo):
從圖表可以輕松看出,用戶主要分布地區(qū),主要以沿海一些發(fā)達城市群為主:


def createCharts(self):
"""生成圖表"""
# 讀取數(shù)據(jù),格式:[{"北京", 10}, {"上海",10}]
data = self.readCityNum()
# 1 熱點圖
geo1 = Geo("《無名之輩》觀眾位置分布熱點圖", "數(shù)據(jù)來源:貓眼,F(xiàn)ly采集", title_color="#FFF", title_pos="center", width="100%", height=600, background_color="#404A59")
attr1, value1 = geo1.cast(data)
geo1.add("", attr1, value1, type="heatmap", visual_range=[0, 1000], visual_text_color="#FFF", symbol_size=15, is_visualmap=True, is_piecewise=False, visual_split_number=10)
geo1.render("files/無名之輩-觀眾位置熱點圖.html")
# 2 位置圖
geo2 = Geo("《無名之輩》觀眾位置分布", "數(shù)據(jù)來源:貓眼,F(xiàn)ly采集", title_color="#FFF", title_pos="center", width="100%", height=600,
background_color="#404A59")
attr2, value2 = geo1.cast(data)
geo2.add("", attr2, value2, visual_range=[0, 1000], visual_text_color="#FFF", symbol_size=15,
is_visualmap=True, is_piecewise=False, visual_split_number=10)
geo2.render("files/無名之輩-觀眾位置圖.html")
# 3、top20 柱狀圖
data_top20 = data[:20]
bar = Bar("《無名之輩》觀眾來源排行 TOP20", "數(shù)據(jù)來源:貓眼,F(xiàn)ly采集", title_pos="center", width="100%", height=600)
attr, value = bar.cast(data_top20)
bar.add('', attr, value, is_visualmap=True, visual_range=[0, 3500], visual_text_color="#FFF", is_more_utils=True, is_label_show=True)
bar.render("files/無名之輩-觀眾來源top20.html")
print("圖表生成完成")
3.2、制作觀眾人數(shù)TOP20的柱形圖,(pyecharts-bar):

3.3、制作評論詞云,(jieba、wordcloud):

生成詞云核心代碼:
def createWordCloud(self):
"""生成評論詞云"""
comments = self.readAllComments() # 19185
# 使用 jieba 分詞
commens_split = jieba.cut(str(comments), cut_all=False)
words = ''.join(commens_split)
# 給詞庫添加停止詞
stopwords = STOPWORDS.copy()
stopwords.add("電影")
stopwords.add("一部")
stopwords.add("無名之輩")
stopwords.add("一部")
stopwords.add("一個")
stopwords.add("有點")
stopwords.add("覺得")
# 加載背景圖片
bg_image = plt.imread("files/2048_bg.png")
# 初始化 WordCloud
wc = WordCloud(width=1200, height=600, background_color='#FFF', mask=bg_image, font_path='C:/Windows/Fonts/STFANGSO.ttf', stopwords=stopwords, max_font_size=400, random_state=50)
# 生成,顯示圖片
wc.generate_from_text(words)
plt.imshow(wc)
plt.axis('off')
plt.show()
四、修改pyecharts源碼
4.1、樣本數(shù)據(jù)的城市簡稱與數(shù)據(jù)集完整城市名匹配不上:
使用位置熱點圖時候,由于采集數(shù)據(jù)城市是一些簡稱,與pyecharts的已存在數(shù)據(jù)的城市名對不上,所以對源碼進行一些修改,方便匹配一些簡稱。
黔南 =>黔南布依族苗族自治州
模塊自帶的全國主要市縣經(jīng)緯度在:[python安裝路徑]\Lib\site-packages\pyecharts\datasets\city_coordinates.json
由于默認情況下,一旦城市名不能完全匹配就會報異常,程序會停止,所以對源碼修改如下(報錯方法為 Geo.add()),其中添加注析為個人修改部分:
def get_coordinate(self, name, region="中國", raise_exception=False):
"""
Return coordinate for the city name.
:param name: City name or any custom name string.
:param raise_exception: Whether to raise exception if not exist.
:return: A list like [longitude, latitude] or None
"""
if name in self._coordinates:
return self._coordinates[name]
coordinate = get_coordinate(name, region=region)
# [ 20181204 添加
# print(name, coordinate)
if coordinate is None:
# 如果字典key匹配不上,嘗試進行模糊查詢
search_res = search_coordinates_by_region_and_keyword(region, name)
# print("###",search_res)
if search_res:
coordinate = sorted(search_res.values())[0]
# 20181204 添加 ]
if coordinate is None and raise_exception:
raise ValueError("No coordinate is specified for {}".format(name))
return coordinate
相應(yīng)的需要對 __add()方法進行如下修改:

五、附錄-源碼
*說明:源碼為本人所寫,數(shù)據(jù)來源為貓眼,全部內(nèi)容僅供學(xué)習(xí),拒絕其他用途!轉(zhuǎn)發(fā)請注明出處!
5.1 采集源碼
# -*- coding:utf-8 -*-
import requests
from datetime import datetime, timedelta
import os
import time
import sys
class MaoyanFilmReviewSpider:
"""貓眼影評爬蟲"""
def __init__(self, url, end_time, filename):
# 頭部
self.headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1'
}
# 目標URL
self.target_url = url
# 數(shù)據(jù)獲取時間段,start_time:截止日期,end_time:上映時間
now = datetime.now()
# 獲取當天的 零點
self.start_time = now + timedelta(hours=-now.hour, minutes=-now.minute, seconds=-now.second)
self.start_time = self.start_time.replace(microsecond=0)
self.end_time = datetime.strptime(end_time, "%Y-%m-%d %H:%M:%S")
# 打開寫入文件, 創(chuàng)建目錄
self.save_path = "files/"
if not os.path.exists(self.save_path):
os.makedirs(self.save_path)
self.save_file = open(self.save_path + filename, "a", encoding="utf-8")
def download(self, url):
"""下載html內(nèi)容"""
print("正在下載URL: "+url)
# 下載html內(nèi)容
response = requests.get(url, headers=self.headers)
# 轉(zhuǎn)成json格式數(shù)據(jù)
if response.status_code == 200:
return response.json()
else:
# print(html.status_code)
print('下載數(shù)據(jù)為空!')
return ""
def parse(self, content):
"""分析數(shù)據(jù)"""
comments = []
try:
for item in content['cmts']:
comment = {
'nickName': item['nickName'], # 昵稱
'cityName': item['cityName'], # 城市
'content': item['content'], # 評論內(nèi)容
'score': item['score'], # 評分
'startTime': item['startTime'], # 時間
}
comments.append(comment)
except Exception as e:
print(e)
finally:
return comments
def save(self, data):
"""寫入文件"""
print("保存數(shù)據(jù),寫入文件中...")
self.save_file.write(data)
def start(self):
"""啟動控制方法"""
print("爬蟲開始...\r\n")
start_time = self.start_time
end_time = self.end_time
num = 1
while start_time > end_time:
print("執(zhí)行次數(shù):", num)
# 1、下載html
content = self.download(self.target_url + str(start_time))
# 2、分析獲取關(guān)鍵數(shù)據(jù)
comments = ''
if content != "":
comments = self.parse(content)
if len(comments) <= 0:
print("本次數(shù)據(jù)量為:0,退出爬?。r\n")
break
# 3、寫入文件
res = ''
for cmt in comments:
res += "%s###%s###%s###%s###%s\n" % (cmt['nickName'], cmt['cityName'], cmt['content'], cmt['score'], cmt['startTime'])
self.save(res)
print("本次數(shù)據(jù)量:%s\r\n" % len(comments))
# 獲取最后一條數(shù)據(jù)的時間 ,然后減去一秒
start_time = datetime.strptime(comments[len(comments) - 1]['startTime'], "%Y-%m-%d %H:%M:%S") + timedelta(seconds=-1)
# start_time = datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S")
# 休眠3s
num += 1
time.sleep(3)
self.save_file.close()
print("爬蟲結(jié)束...")
if __name__ == "__main__":
# 確保輸入?yún)?shù)
if len(sys.argv) != 4:
print("請輸入相關(guān)參數(shù):[moveid]、[上映日期]和[保存文件名],如:xxx.py 42962 2018-11-09 text.txt")
exit()
# 貓眼電影ID
mid = sys.argv[1] # "1208282" # "42964"
# 電影上映日期
end_time = sys.argv[2] # "2018-11-16" # "2018-11-09"
# 每次爬取條數(shù)
offset = 15
# 保存文件名
filename = sys.argv[3]
spider = MaoyanFilmReviewSpider(url="http://m.maoyan.com/mmdb/comments/movie/%s.json?v=yes&offset=%d&startTime=" % (mid, offset), end_time="%s 00:00:00" % end_time, filename=filename)
# spider.start()
spider.start()
# t1 = "2018-11-09 23:56:23"
# t2 = "2018-11-25"
#
# res = datetime.strptime(t1, "%Y-%m-%d %H:%M:%S") + timedelta(days=-1)
# print(type(res))
MaoyanFilmReviewSpider.py
5.2 分析制圖源碼
# -*- coding:utf-8 -*-
from pyecharts import Geo, Bar, Bar3D
import jieba
from wordcloud import STOPWORDS, WordCloud
import matplotlib.pyplot as plt
class ACoolFishAnalysis:
"""無名之輩 --- 數(shù)據(jù)分析"""
def __init__(self):
pass
def readCityNum(self):
"""讀取觀眾城市分布數(shù)量"""
d = {}
with open("files/myCmts2.txt", "r", encoding="utf-8") as f:
row = f.readline()
while row != "":
arr = row.split('###')
# 確保每條記錄長度為 5
while len(arr) < 5:
row += f.readline()
arr = row.split('###')
# 記錄每個城市的人數(shù)
if arr[1] in d:
d[arr[1]] += 1
else:
d[arr[1]] = 1 # 首次加入字典,為 1
row = f.readline()
# print(len(comments))
# print(d)
# 字典 轉(zhuǎn) 元組數(shù)組
res = []
for ks in d.keys():
if ks == "":
continue
tmp = (ks, d[ks])
res.append(tmp)
# 按地點人數(shù)降序
res = sorted(res, key=lambda x: (x[1]),reverse=True)
return res
def readAllComments(self):
"""讀取所有評論"""
comments = []
# 打開文件讀取數(shù)據(jù)
with open("files/myCmts2.txt", "r", encoding="utf-8") as f:
row = f.readline()
while row != "":
arr = row.split('###')
# 每天記錄長度為 5
while len(arr) < 5:
row += f.readline()
arr = row.split('###')
if len(arr) == 5:
comments.append(arr[2])
# if len(comments) > 20:
# break
row = f.readline()
return comments
def createCharts(self):
"""生成圖表"""
# 讀取數(shù)據(jù),格式:[{"北京", 10}, {"上海",10}]
data = self.readCityNum()
# 1 熱點圖
geo1 = Geo("《無名之輩》觀眾位置分布熱點圖", "數(shù)據(jù)來源:貓眼,F(xiàn)ly采集", title_color="#FFF", title_pos="center", width="100%", height=600, background_color="#404A59")
attr1, value1 = geo1.cast(data)
geo1.add("", attr1, value1, type="heatmap", visual_range=[0, 1000], visual_text_color="#FFF", symbol_size=15, is_visualmap=True, is_piecewise=False, visual_split_number=10)
geo1.render("files/無名之輩-觀眾位置熱點圖.html")
# 2 位置圖
geo2 = Geo("《無名之輩》觀眾位置分布", "數(shù)據(jù)來源:貓眼,F(xiàn)ly采集", title_color="#FFF", title_pos="center", width="100%", height=600,
background_color="#404A59")
attr2, value2 = geo1.cast(data)
geo2.add("", attr2, value2, visual_range=[0, 1000], visual_text_color="#FFF", symbol_size=15,
is_visualmap=True, is_piecewise=False, visual_split_number=10)
geo2.render("files/無名之輩-觀眾位置圖.html")
# 3、top20 柱狀圖
data_top20 = data[:20]
bar = Bar("《無名之輩》觀眾來源排行 TOP20", "數(shù)據(jù)來源:貓眼,F(xiàn)ly采集", title_pos="center", width="100%", height=600)
attr, value = bar.cast(data_top20)
bar.add('', attr, value, is_visualmap=True, visual_range=[0, 3500], visual_text_color="#FFF", is_more_utils=True, is_label_show=True)
bar.render("files/無名之輩-觀眾來源top20.html")
print("圖表生成完成")
def createWordCloud(self):
"""生成評論詞云"""
comments = self.readAllComments() # 19185
# 使用 jieba 分詞
commens_split = jieba.cut(str(comments), cut_all=False)
words = ''.join(commens_split)
# 給詞庫添加停止詞
stopwords = STOPWORDS.copy()
stopwords.add("電影")
stopwords.add("一部")
stopwords.add("無名之輩")
stopwords.add("一部")
stopwords.add("一個")
stopwords.add("有點")
stopwords.add("覺得")
# 加載背景圖片
bg_image = plt.imread("files/2048_bg.png")
# 初始化 WordCloud
wc = WordCloud(width=1200, height=600, background_color='#FFF', mask=bg_image, font_path='C:/Windows/Fonts/STFANGSO.ttf', stopwords=stopwords, max_font_size=400, random_state=50)
# 生成,顯示圖片
wc.generate_from_text(words)
plt.imshow(wc)
plt.axis('off')
plt.show()
if __name__ == "__main__":
demo = ACoolFishAnalysis()
demo.createWordCloud()
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
OpenCV-Python 實現(xiàn)兩張圖片自動拼接成全景圖
圖片的全景拼接如今已不再稀奇,現(xiàn)在的智能攝像機和手機攝像頭基本都帶有圖片自動全景拼接的功能,本文使用OpenCV-Python 實現(xiàn)兩張圖片自動拼接成全景圖,感興趣的可以了解一下2021-06-06
Django-Rest-Framework 權(quán)限管理源碼淺析(小結(jié))
這篇文章主要介紹了Django-Rest-Framework 權(quán)限管理源碼淺析(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11
FP-growth算法發(fā)現(xiàn)頻繁項集——發(fā)現(xiàn)頻繁項集
常見的挖掘頻繁項集算法有兩類,一類是Apriori算法,另一類是FP-growth。Apriori通過不斷的構(gòu)造候選集、篩選候選集挖掘出頻繁項集,需要多次掃描原始數(shù)據(jù),當原始數(shù)據(jù)較大時,磁盤I/O次數(shù)太多,效率比較低下2021-06-06

