標籤:ESS 圖形 做了 date 地理 response arm 鄭州 legend
黃渤首次導演的電影《一出好戲》自8月10日在全國上映,至今已有10天,其主演陣容強大,相信許多觀眾也都是衝著明星們去的。
目前《一出好戲》在貓眼上已經獲得近60萬個評價,評分為8.2分,票房已破10億。
作者本人(湯小洋 )今天也走進了電影院,對這部電影做了親身的觀看,看完後的感覺是有些許失落的,本以為是喜劇片,結果發現笑點一般,從搞笑的角度來看,不如《西虹市首富》,影片更多的是反映人類本性的一部電影,不應當做喜劇片來看,影片中展現的人與人之間的關係倒是值得我們去深思。
今天就跟著 湯老師 一起來揭秘影片《一出好戲》,看看“這出好戲”到底如何?
我們將使用Python抓取貓眼近10萬條評論資料,並對擷取到的資料進行分析,看看觀眾對這部電影的評價究竟如何?
整個資料分析的過程分為四步:
- 擷取資料
- 處理資料
- 儲存資料
- 資料視覺效果
一、擷取資料1. 簡介
? 本次擷取的是貓眼APP的評論資料,:
通過分析發現貓眼APP的評論資料介面為:
http://m.maoyan.com/mmdb/comments/movie/1200486.json?_v_=yes&offset=0&startTime=2018-07-28%2022%3A25%3A03
? 通過對評論資料進行分析,得到如下資訊:
2. 代碼實現
? 這裡先定義一個函數,用來根據指定url擷取資料,且只能擷取到指定的日期向前擷取到15條評論資料
# coding=utf-8__author__ = ‘湯小洋‘from urllib import requestimport jsonimport timefrom datetime import datetimefrom datetime import timedelta# 擷取資料,根據url擷取def get_data(url): headers = { ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36‘ } req = request.Request(url, headers=headers) response = request.urlopen(req) if response.getcode() == 200: return response.read() return Noneif __name__ == ‘__main__‘: html = get_data(‘http://m.maoyan.com/mmdb/comments/movie/1200486.json?_v_=yes&offset=0&startTime=2018-07-28%2022%3A25%3A03‘) print(html)
二、處理資料
對擷取的資料進行處理,轉換為json
# 處理資料def parse_data(html): data = json.loads(html)[‘cmts‘] # 將str轉換為json comments = [] for item in data: comment = { ‘id‘: item[‘id‘], ‘nickName‘: item[‘nickName‘], ‘cityName‘: item[‘cityName‘] if ‘cityName‘ in item else ‘‘, # 處理cityName不存在的情況 ‘content‘: item[‘content‘].replace(‘\n‘, ‘ ‘, 10), # 處理評論內容換行的情況 ‘score‘: item[‘score‘], ‘startTime‘: item[‘startTime‘] } comments.append(comment) return commentsif __name__ == ‘__main__‘: html = get_data(‘http://m.maoyan.com/mmdb/comments/movie/1200486.json?_v_=yes&offset=0&startTime=2018-07-28%2022%3A25%3A03‘) comments = parse_data(html) print(comments)
三、儲存資料
? 為了能夠擷取到所有評論資料,方法是:從目前時間開始,向前擷取資料,根據url每次擷取15條,然後得到末尾評論的時間,從該時間繼續向前擷取資料,直到影片上映日期(2018-08-10)為止,擷取這之間的所有資料。
# 儲存資料,儲存到文字檔def save_to_txt(): start_time = datetime.now().strftime(‘%Y-%m-%d %H:%M:%S‘) # 擷取目前時間,從目前時間向前擷取 end_time = ‘2018-08-10 00:00:00‘ while start_time > end_time: url = ‘http://m.maoyan.com/mmdb/comments/movie/1203084.json?_v_=yes&offset=0&startTime=‘ + start_time.replace(‘ ‘, ‘%20‘) html = None ‘‘‘ 問題:當請求過於頻繁時,伺服器會拒絕串連,實際上是伺服器的反爬蟲策略 解決:1.在每個請求間增加延時0.1秒,盡量減少請求被拒絕 2.如果被拒絕,則0.5秒後重試 ‘‘‘ try: html = get_data(url) except Exception as e: time.sleep(0.5) html = get_data(url) else: time.sleep(0.1) comments = parse_data(html) print(comments) start_time = comments[14][‘startTime‘] # 獲得末尾評論的時間 start_time = datetime.strptime(start_time, ‘%Y-%m-%d %H:%M:%S‘) + timedelta(seconds=-1) # 轉換為datetime類型,減1秒,避免擷取到重複資料 start_time = datetime.strftime(start_time, ‘%Y-%m-%d %H:%M:%S‘) # 轉換為str for item in comments: with open(‘comments.txt‘, ‘a‘, encoding=‘utf-8‘) as f: f.write(str(item[‘id‘])+‘,‘+item[‘nickName‘] + ‘,‘ + item[‘cityName‘] + ‘,‘ + item[‘content‘] + ‘,‘ + str(item[‘score‘])+ ‘,‘ + item[‘startTime‘] + ‘\n‘)if __name__ == ‘__main__‘: # html = get_data(‘http://m.maoyan.com/mmdb/comments/movie/1200486.json?_v_=yes&offset=0&startTime=2018-07-28%2022%3A25%3A03‘) # comments = parse_data(html) # print(comments) save_to_txt()
? 有兩點需要說明:
- 伺服器一般都有反爬蟲策略,當請求過於頻繁時,伺服器會拒絕部分串連,我這裡是通過增加每個請求間延時來解決,只是一種簡單的解決方案,還望各位看客理解包涵
- 根據資料量的多少,抓取資料所需時間會有所不同,我抓取的是2018-8-19到2018-8-10(上映當天)之間的資料,大概花了2個小時,共抓取約9.2萬條評論資料
四、資料視覺效果
? 這裡使用的是pyecharts,pyecharts是一個用於產生Echarts圖表的類庫,便於在Python中根據資料產生可視化的圖表。
? Echarts是百度開源的一個資料視覺效果JS庫,主要用於資料視覺效果。
? 參考:http://pyecharts.org/
# 安裝pyechartspip install pyecharts
? pyecharts v0.3.2以後,pyecharts 將不再內建地圖 js 檔案。如使用者需要用到地圖圖表,可自行安裝對應的地圖檔案包。
# 安裝地圖檔案包pip install echarts-china-provinces-pypkg # 中國省、市、縣、區地圖pip install echarts-china-cities-pypkgpip install echarts-china-counties-pypkgpip install echarts-china-misc-pypkg pip install echarts-countries-pypkg # 全球國家地圖pip install echarts-united-kingdom-pypkg
1. 粉絲位置分布
? 代碼實現
# 匯入Style類,用於定義樣式風格from pyecharts import Style# 匯入Geo組件,用於產生地理座標類圖from pyecharts import Geoimport json# 匯入Geo組件,用於產生柱狀圖from pyecharts import Bar# 匯入Counter類,用於統計值出現的次數from collections import Counter# 資料視覺效果def render(): # 擷取評論中所有城市 cities = [] with open(‘comments.txt‘, mode=‘r‘, encoding=‘utf-8‘) as f: rows = f.readlines() for row in rows: city = row.split(‘,‘)[2] if city != ‘‘: # 去掉城市名為空白的值 cities.append(city) # 對城市資料和座標檔案中的地名進行處理 handle(cities) # 統計每個城市出現的次數 # data = [] # for city in set(cities): # data.append((city, cities.count(city))) data = Counter(cities).most_common() # 使用Counter類統計出現的次數,並轉換為元組列表 # print(data) # 定義樣式 style = Style( title_color=‘#fff‘, title_pos=‘center‘, width=1200, height=600, background_color=‘#404a59‘ ) # 根據城市資料產生地理座標圖 geo = Geo(‘《一出好戲》粉絲位置分布‘, ‘資料來源:貓眼-湯小洋採集‘, **style.init_style) attr, value = geo.cast(data) geo.add(‘‘, attr, value, visual_range=[0, 3500], visual_text_color=‘#fff‘, symbol_size=15, is_visualmap=True, is_piecewise=True, visual_split_number=10) geo.render(‘粉絲位置分布-地理座標圖.html‘) # 根據城市資料產生柱狀圖 data_top20 = Counter(cities).most_common(20) # 返回出現次數最多的20條 bar = Bar("《一出好戲》粉絲來源排行TOP20", "資料來源:貓眼-湯小洋採集", title_pos=‘center‘, width=1200, height=60) 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("粉絲來源排行-柱狀圖.html")
? 出現的問題:
報錯:ValueError: No coordinate is specified for xxx(地名)
原因:pyecharts的座標檔案中沒有該地名,實際上是名稱不一致導致的,如資料中地名為‘達州‘,而座標檔案中為‘達州市‘
座標檔案所在路徑:項目/venv/lib/python3.6/site-packages/pyecharts/datasets/city_coordinates.json
- 解決:修改座標檔案,在原位置下複製個同樣的,然後修改下地名
{ "達州市": [ 107.5, 31.22 ], "達州": [ 107.5, 31.22 ],}
? 不過由於要修改的地名太多,上面的方法實在是麻煩,所以我定義了一個函數,用來處理地名資料找不到的問題
# 處理地名資料,解決座標檔案中找不到地名的問題def handle(cities): # print(len(cities), len(set(cities))) # 擷取座標檔案中所有地名 data = None with open( ‘/Users/wangbo/PycharmProjects/python-spider/venv/lib/python3.6/site-packages/pyecharts/datasets/city_coordinates.json‘, mode=‘r‘, encoding=‘utf-8‘) as f: data = json.loads(f.read()) # 將str轉換為json # 迴圈判斷處理 data_new = data.copy() # 拷貝所有地名資料 for city in set(cities): # 使用set去重 # 處理地名為空白的資料 if city == ‘‘: while city in cities: cities.remove(city) count = 0 for k in data.keys(): count += 1 if k == city: break if k.startswith(city): # 處理簡寫的地名,如 達州市 簡寫為 達州 # print(k, city) data_new[city] = data[k] break if k.startswith(city[0:-1]) and len(city) >= 3: # 處理行政變更的地名,如縣改區 或 縣改市等 data_new[city] = data[k] break # 處理不存在的地名 if count == len(data): while city in cities: cities.remove(city) # print(len(data), len(data_new)) # 寫入覆蓋座標檔案 with open( ‘/Users/wangbo/PycharmProjects/python-spider/venv/lib/python3.6/site-packages/pyecharts/datasets/city_coordinates.json‘, mode=‘w‘, encoding=‘utf-8‘) as f: f.write(json.dumps(data_new, ensure_ascii=False)) # 將json轉換為str
可視化結果:
粉絲人群主要集中在沿海一帶
從可以看出,《一出好戲》的觀影人群主要集中在沿海一帶,這些地方經濟相對發達,城市人口基數龐大,極多的熒幕數量和座位、極高密度的排片場次,讓觀眾便捷觀影,活躍的觀眾評論也多,自然也就成為票房的主要貢獻者。
粉絲來源排名前20的城市依次為:北京、深圳、上海、成都、武漢、廣州、西安、鄭州、重慶、南京、天津、瀋陽、長沙、東莞、哈爾濱、青島、杭州、合肥、大連、蘇州
電影消費是城市消費的一部分,從某種角度來看,可以作為考察一個城市購買力的指標。這些城市在近年的GDP排行中大都居上遊,消費水平較高。
2. 詞雲圖
? jieba是一個基於Python的分詞庫,完美支援中文分詞,功能強大
pip install jieba
? Matplotlib是一個Python的2D繪圖庫,能夠產生高品質的圖形,可以快速產生繪圖、長條圖、功率譜、柱狀圖、誤差圖、散佈圖等
pip install matplotlib
? wordcloud是一個基於Python的詞雲產生類庫,可以產生詞雲圖
pip install wordcloud
? 代碼實現:
# coding=utf-8__author__ = "湯小洋"# 匯入jieba模組,用於中文分詞import jieba# 匯入matplotlib,用於產生2D圖形import matplotlib.pyplot as plt# 匯入wordcount,用於製作詞雲圖from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator# 擷取所有評論comments = []with open(‘comments.txt‘, mode=‘r‘, encoding=‘utf-8‘) as f: rows = f.readlines() for row in rows: comment = row.split(‘,‘)[3] if comment != ‘‘: comments.append(comment)# 設定分詞comment_after_split = jieba.cut(str(comments), cut_all=False) # 非全模式分詞,cut_all=falsewords = " ".join(comment_after_split) # 以空格進行拼接# print(words)# 設定屏蔽詞stopwords = STOPWORDS.copy()stopwords.add("電影")stopwords.add("一部")stopwords.add("一個")stopwords.add("沒有")stopwords.add("什麼")stopwords.add("有點")stopwords.add("這部")stopwords.add("這個")stopwords.add("不是")stopwords.add("真的")stopwords.add("感覺")stopwords.add("覺得")stopwords.add("還是")stopwords.add("但是")stopwords.add("就是")# 匯入背景圖bg_image = plt.imread(‘bg.jpg‘)# 設定詞雲參數,參數分別表示:畫布寬高、背景顏色、背景圖形狀、字型、屏蔽詞、最大詞的字型大小wc = WordCloud(width=1024, height=768, background_color=‘white‘, mask=bg_image, font_path=‘STKAITI.TTF‘, stopwords=stopwords, max_font_size=400, random_state=50)# 將分詞後資料傳入雲圖wc.generate_from_text(words)plt.imshow(wc)plt.axis(‘off‘) # 不顯示座標軸plt.show()# 儲存結果到本地wc.to_file(‘詞雲圖.jpg‘)
可視化結果:
總體評價很不錯
? 對評論資料進行分詞後製作如下詞雲圖:
? 從詞雲圖中可以看到:
- 評論中多次出現“可以”、“好看”、“不錯”等熱詞,說明觀眾對《一出好戲》的總體評價還是很不錯的
- 同時對該影片中“張藝興”的“演技”也給予了很大的認可,我本人今天在觀看後也有同感,讓我們看到了不一樣的張藝興,實力演員
- 對於初次“導演”電影的“黃渤”,能拍出這樣的影片,粉絲們也是比較肯定的,同時其本身就是票房的保障
- 至於劇情方面,“現實”、“喜劇”、“搞笑”、“故事”等詞語,能看出這是一部反映現實的故事片,同時也兼具喜劇搞笑
- 對於評論中出現的“一般”、“失望”等,這些粉絲或許是和我一樣,本以為這是一部爆笑喜劇片,笑點應該會很多(畢竟在我們心中,黃渤、王寶強等就是諧星),沒想到笑點並不很多,至少與期待的有差距,導致心裡有落差的原因吧^_^
3. 評分星級
? 代碼實現:
# coding=utf-8__author__ = "湯小洋"# 匯入Pie組件,用於產生餅圖from pyecharts import Pie# 擷取評論中所有評分rates = []with open(‘comments.txt‘, mode=‘r‘, encoding=‘utf-8‘) as f: rows = f.readlines() for row in rows: rates.append(row.split(‘,‘)[4])# print(rates)# 定義星級,並統計各星級評等數量attr = ["五星", "四星", "三星", "二星", "一星"]value = [ rates.count(‘5‘) + rates.count(‘4.5‘), rates.count(‘4‘) + rates.count(‘3.5‘), rates.count(‘3‘) + rates.count(‘2.5‘), rates.count(‘2‘) + rates.count(‘1.5‘), rates.count(‘1‘) + rates.count(‘0.5‘)]# print(value)pie = Pie(‘《一出好戲》評分星級比例‘, title_pos=‘center‘, width=900)pie.add("7-17", attr, value, center=[75, 50], is_random=True, radius=[30, 75], rosetype=‘area‘, is_legend_show=False, is_label_show=True)pie.render(‘評分.html‘)
可視化結果:
四、五星級影評合計高達83%
? 可以看出,五星比例接近62%,四星比例為21%,兩者合計高達83%,可見口碑還是相當不錯的,一星佔比不足6%
? 《一出好戲》作為黃渤第一次執導的作品,在拍攝過程中導演渤哥對自己的要求也是很嚴格的,所以有這樣的成績,也是理所當然。
附:今天看電影的票根 ^_^
《一出好戲》講述人性,使用Python抓取貓眼近10萬條評論並分析,一起揭秘“這出好戲”到底如何?