最近幾年貓眼電影愈來愈熱門了,都差很少和豆瓣並駕齊驅了。今年的《流浪地球》這麼火,經過爬取貓眼電影上網友對該片的評價如何。javascript
先打開貓眼官網找到《流浪地球》的介紹頁面:https://maoyan.com/films/248906java
雖然顯示有112.4萬人評分,可是頁面只有熱門短評,其餘評論都去哪裏了,手機明明是有的。python
那麼咱們用chrome
切換到手機頁面:git
這時候咱們就看到了全部的評論。github
在點擊打開「查看所有330613條討論」後,發現評論分爲最熱和最新兩部分,最熱數量有限,而最新則是未通過處理的,也正是咱們須要的。經過search
來查看下對應的請求:web
發現,在chrome
的網絡展現中發現只有一個類型爲document
的請求包含了所需的信息。那麼這部分的評論獲取就須要解析網頁了,咱們再把屏幕上的評論往下拉,發現會自動加載更多的評論,對應的chrome
網絡請求多出來了兩個comments.json
的請求:chrome
果真這纔是咱們須要的!把初始頁面的url
和這兩個json
請求的url
複製到一塊兒比較一下:shell
http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=0&limit=15&ts=0&type=3 http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=15&limit=15&ts=1549965527295&type=3 http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=30&limit=15&ts=1549965527295&type=3
咱們能夠發現規律:json
ts
值爲0,隨後會有ts
值,且保持不變。這裏的ts
是當前的時間戳,能夠經過轉換工具查看:
再看返回的json
結果:api
data.comments
中是評論的具體內容paging
中經過hasMore
來告訴咱們是否還有更多(判斷是否繼續抓取)咱們再嘗試下將offset
設置爲0,也加上ts
參數:
http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=0&limit=15&ts=1549965527295&type=3
發現也是能夠獲取數據的:
那麼經過offset
和limit
來控制每次請求獲取的數量。
咱們還能夠經過加大limit
參數來嘗試,是否能夠一次性獲取更多的評論:
http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=0&limit=30&ts=1549965527295&type=3
效果以下:
再增長limit
的值,會發現評論數回到了15
條,可見貓眼系統僅支持每次最多獲取30條。
根據上面的分析,咱們構造請求的url
就很明確了:
offset=0&limit=30
開始paging.hasMore
來判斷是否繼續抓取url
中offset+=limit
根據上述分析,在返回的json
數據中是能夠看到總評論數的,可是實際抓取的時候,在offset
超過1000以後,返回的數據中hasMore
就變成了false
。
因而嘗試經過瀏覽器一直下拉刷新,到達offset
超過1000的狀況,發現頁面會不停的發送請求,但也沒法獲取數據。
那應該就是網站作了控制,不容許offset
超過1000。
那麼就要考慮其餘構造url的方法來抓取了。先觀察下每一個請求返回的信息:
發現每一個comment
裏都包含有一個time
信息,把time
作一下處理:
2019-02-13 13:38:00##感受韓朵朵這我的設是多餘的 2019-02-13 13:38:00##真的感動 很是棒 2019-02-13 13:38:00##這電影大陸的起航 2019-02-13 13:38:00##不怎麼樣,劇情挺感人,可是有點尷尬 2019-02-13 13:37:00##好看。。。。。。。。。。 2019-02-13 13:37:00##超級超級超級超級超級超級超級好看 2019-02-13 13:37:00##太牛逼了,中國科幻片可有一部能看的了。支持吳京 2019-02-13 13:36:00##不錯!中國科幻的但願 2019-02-13 13:36:00##中國里程碑式的科幻電影。 2019-02-13 13:36:00##什麼垃圾座位沒人管的麼亂坐的
能夠發現後臺是按照時間順序的,每分鐘一個間隔,那麼就能夠考慮根據每次返回comment
中的時間來更新url
中的ts
便可。
因爲不肯定每次請求返回的數據中包含了多長的時間段,且返回的第一個評論時間戳與第二個評論是不一樣的,因此抓取思路以下:
ts
設置爲第二個時間戳,從新構造url
offset
來繼續抓取,直到遇到第三個時間戳根據上面思路,實現相對就比較簡單了:
生成url
def get_url(): global offset url = 'http://m.maoyan.com/review/v2/comments.json?movieId=' + movieId + '&userId=-1&offset=' + str( offset) + '&limit=' + str(limit) + '&ts=' + str(ts) + '&type=3' return url
訪問url
def open_url(url): global ua try: headers = {'User-Agent': ua.random} response = requests.get(url, headers=headers) if response.status_code == 200: return response.text else: return None except Exception as e: print(e) return None
數據處理:將評論保存並判斷是否要繼續抓取
def parse_json(data): global count global offset global limit global ts ts_duration = ts res = json.loads(data) comments = res['data']['comments'] for comment in comments: comment_time = comment['time'] if ts == 0: ts = comment_time ts_duration = comment_time if comment_time != ts and ts == ts_duration: ts_duration = comment_time if comment_time !=ts_duration: ts = ts_duration offset = 0 return get_url() else: content = comment['content'].strip().replace('\n', '。') print('get comment ' + str(count)) count += 1 write_txt(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(comment_time/1000)) + '##' + content + '\n') if res['paging']['hasMore']: offset += limit return get_url() else: return None
最後一共抓取評論131106條,足夠作各類分析了
2019-02-13 18:13:11,625 - get_comments.py[line:78] - INFO: get comment 131104 2019-02-13 18:13:11,729 - get_comments.py[line:78] - INFO: get comment 131105 2019-02-13 18:13:11,827 - get_comments.py[line:78] - INFO: get comment 131106 2019-02-13 18:13:15,416 - get_comments.py[line:98] - INFO: end
前面咱們再抓取時,將評論的時間和內容經過csv
的格式保存下來,並使用;
分割。讀取csv
文件並統計處理就要用到大名鼎鼎的pandas
了。
讀取數據
pandas
提供read_csv
方法來直接獨處數據保存爲DateFrame
格式。
df = pd.read_csv('comment.csv', sep=';', header=None)
設置數據列名
因爲咱們知道數據有兩列,先經過這隻列名能夠方便後續引用。
df.columns = ['date', 'comment']
時間日期處理
在date
列,咱們保存的數據格式是string
,須要把轉換爲日期格式才能進一步處理。
df['date'] = pd.to_datetime(df['date'])
咱們須要按時間來統計,因此把date
列設置爲index
:
df = df.set_index('date')
日期篩選
因爲咱們知道《流浪地球》是2月5日上映的,咱們能夠對日期進行限定,以避免出現有些在上映前的評論,會佔用大段的空白狀況。
設置index
以後,能夠參考list
類型操做,因爲時間是倒序的,因此能夠直接使用[:'2019-02-04']
來選取2月4日以後到今天的全部數據。pandas
在數據篩選方面至關智能,按照datetime
的格式直接篩選便可。
cacu_df = df[:'2019-02-04']
按日期進行數量統計
pandas
中,經過resample
方法進行從新採樣,經過傳入rule
參數就能夠按須要的頻率獲取數據,得到一個resampler
對象。
DataFrame.resample(rule, how=None, axis=0, fill_method=None, closed=None, label=None, convention='start', kind=None, loffset=None, limit=None, base=0, on=None, level=None)
resampler
對象提供了不少的統計方法,好比彙總求和可以使用Resampler.count()
。
# 按日統計數量 cacu = cacu_df.resample('D').count()
這樣就完成了按日期求和統計操做。
繪圖
畫圖須要使用matplotlib
庫,經過導入該庫,可直接對DateFrame
對象進行畫圖處理。畫圖及圖表格式化以下:
# 設置中文字體 font = FontProperties(fname='/System/Library/Fonts/PingFang.ttc') plt.plot(cacu) plt.title("流浪地球評論分析", fontproperties=font) plt.xlabel("日期", fontproperties=font) plt.ylabel("評論數", fontproperties=font) plt.axis("tight") # 顯示網格 plt.grid(True) # 自動旋轉橫軸日期 plt.gcf().autofmt_xdate() # 顯示數值 for a, b in zip(cacu.index, cacu.values): plt.text(a, b, str(b[0])) # 保存圖片 plt.savefig('comment_analysis.png') # 查看圖片 plt.show()
結果以下:
可見從上映以後,關注度直線飆升,到2月10日以後(上映5天),你們關注度逐漸降低。其中2月14日爲情人節,你們的關注又有了小幅的上升。也許不少人在這天經過看《流浪地球》過節吧。
數據清洗
首先因爲評論是用戶發表的,可能什麼字符都會有,要先把一些特殊符號去掉,這裏就用到了正則替換:
msg = re.sub("[\s+\.\!\/_,$%^*()+\"\'\?]+|[+——!,。?、~@#¥%……&*()【】;:]+|\[.+\]|\[.+\]", "", line)
分詞與標籤
清洗後的數據,可使用jieba
分詞包來進行分詞,並把全部的分詞保存在一個list
中,而後計算出每一個分詞出現的次數。
# 分詞 tags = jieba.analyse.extract_tags(msg) for t in tags: word_list.append(t) # 計算詞頻 for word in word_list: if word not in word_dict: word_dict[word] = 1 else: word_dict[word] += 1
生成詞雲
使用wordcloud
包,就能夠很方便的生成詞雲圖片了。
先新建一個WordCloud
對象,進行配置,而後利用前面的分詞詞頻就能夠生成對應的圖片了。
# 計算圖片顏色 alice_coloring = np.array(img) my_wordcloud = WordCloud(background_color="white", max_words=500, mask=alice_coloring, max_font_size=200, random_state=42, font_path=(os.path.join(d, "font/msyh.ttf"))) my_wordcloud = my_wordcloud.generate_from_frequencies(wordList)
這裏須要注意的是:
mask=alice_coloring
:這裏經過numpy
將圖片矩陣化,來獲取圖片的顏色做爲WordCloud
的mask
,是爲了最後生成的圖雲不只外形與咱們輸入的圖片保持一致,並且總體顏色也保持一致。保存圖片
最後使用matplotlib.pyplot
來保存圖片,保存前要進行圖片屬性的一些設置。
width = img.width/80 height = img.height/80 plt.figure(figsize=(width, height)) plt.imshow(my_wordcloud.recolor(color_func=image_colors)) plt.imshow(my_wordcloud) plt.axis("off") # 經過設置subplots_adjust來控制畫面外邊框 plt.subplots_adjust(bottom=.01, top=.99, left=.01, right=.99) plt.savefig("jupiter_wordcloud_1.png") plt.show()
這裏須要注意的是: 建議根據原圖片的長寬比例進行必定的縮小,以避免生成的圖片像素過大而產生報錯。
ValueError: Image size of 98400x46500 pixels is too large. It must be less than 2^16 in each direction.
放一張原圖,你能看的出來嘛,摳圖技術有限O(∩_∩)O哈哈~
以上就是使用抓取的評論生成詞雲的大體思路,完成的實現代碼請見:https://github.com/keejo125/w...
若是有更好的方法,歡迎一塊兒探討。