Python 爬取愛奇藝 52432 條資料分析誰才是《奇葩說》的焦點人物?
版權宣告:本文為博主原創文章,採用知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議進行許可。 https://blog.csdn.net/lovecluo/article/details/84776527
本文首發於 ofollow,noindex" target="_blank">CSDN 微信 (ID:CSDNNews)
作者 | 羅昭成
責編 | 唐小引
五年前,《奇葩說》在愛奇藝開始播出,第一次將辯論賽引入了綜藝節目。雖然專業性很強,但他們努力去凸顯自己與眾不同的個性,展現出自己“奇葩”的一面。每一個辯題,最後結果並不表示官方的意見,而是希望大家在看到節目過後,能夠讓觀眾朋友們思考一些以前沒有考慮過的問題,讓觀眾朋友們看到世界的多元性,而筆者作為一個日常與程式碼為伍的程式員,在家中寫程式碼之時也總喜歡一邊播放著。
經過 5 年的發展,奇葩說已經更新到了第五季,這一季,節目內容還是很精彩。但是很多辯論的時候,“耍無賴”好像比講道理更能贏得觀眾的喜愛。生活不止有眼前苟且,還有詩和遠方。節目組應該沒有去幹擾比賽結果,但是筆者不喜歡“耍無賴”就這麼贏得比賽,因為他對“老實人”不公平。在筆者的眼中,奇葩說變了,不再是我喜歡的那個奇葩說了(以上,僅為作者個人觀點)。
不管如何,奇葩說還是很精彩,每一個辯題,都值得去深入思考。在奇葩說第五季即將完結之際,筆者突發奇想,作為程式設計師,是不是可以換一種角度來看奇葩說?在本文中,筆者以技術手段對奇葩說官方資料進行了分析,希望能夠有一點幫助。
爬取資料
奇葩說是愛奇藝獨播視訊,所以這一次,筆者選取官方評論資料作為資源庫,來進行資料分析。
使用 Chrome 檢視原始碼模式,在“奇葩說”播放頁面往下面滑動,有一個 get_comments 的請求,經過分析,這個介面就是獲取評論資料的介面。
看一下介面地址和請求引數:
介面地址: http://sns-comment.iqiyi.com/v3/comment/get_comments.action 引數: "types":"time" "business_type":"17" "agent_type":"119" "agent_version":"9.9.0" "authcookie":"cookie" "last_id": "" "content_id": ""
其中 last_id 是用來進行分頁的。
- 使用 Python 獲取資料
上面的請求使用的 GET 方式,請求程式碼如下:
def saveMoveInfoToFile(movieId, movieName, lastId): url = "http://sns-comment.iqiyi.com/v3/comment/get_comments.action?" params = { "types":"time", "business_type":"17", "agent_type":"119", "agent_version":"9.9.0", "authcookie":"authcookie" } if lastId != "": params["last_id"] =lastId for item in params: url = url + item + "=" + params[item] + "&" url = url + "content_id=" + movieId responseTxt = getMoveinfo(url) def getMoveinfo(url): session = requests.Session() headers = { "User-Agent": "Mozilla/5.0", "Accept": "application/json", "Referer": "http://m.iqiyi.com/v_19rqriflzg.html", "Origin": "http://m.iqiyi.com", "Host": "sns-comment.iqiyi.com", "Connection": "keep-alive", "Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6", "Accept-Encoding": "gzip, deflate" } response = session.get(url, headers=headers) if response.status_code == 200: return response.text return None
請求返回的資料是 JSON ,這裡筆者就不貼返回資料,直接解析儲存。本處,筆者使用 SQLite3 進行資料儲存。
- 解析資料
def parseData(movieId, movieName, htmlContent): data = json.loads(htmlContent)['data']['comments'] lastId = "-1" if json.dumps(data) == "[]": return lastId lastId = "-1" for item in data: originalData = json.dumps(item) saveOriginalDataToDatabase(item["id"], movieId, movieName, originalData) lastId = item['id'] return lastId
為了更方便後續進行資料分析,所以將拉下來的評論資料全部進行儲存,防止多次去爬取資料。
資料儲存在資料庫中非常簡單,一個簡單的 insert 語句就可以搞定。程式碼如下:
def saveOriginalDataToDatabase(msgId, movieId, movieName, originalData): conn = sqlite3.connect('i_can_i_bb.db') conn.text_factory = str cursor = conn.cursor() ins="insert into originalData values (?,?,?,?)" v = (movieId+ "_" + msgId, movieId, originalData, movieName) cursor.execute(ins, v) cursor.close() conn.commit() conn.close()
本次總共從愛奇藝抓取了 52432 條評論資料。
資料清洗與整理
從愛奇藝抓取的資料,並不是所有的資料我們都需要,這裡,只需將我們想要的資料提取出來。
- 提取資料
此處將使用者的個人資訊、評論、評論時間、性別等資料提取出來,儲存到另一張表中。後續資料分析就從新的表中拿取就可以了,處理邏輯如下:
def saveRealItem(id, originalData): user = json.loads(originalData) conn = sqlite3.connect('deal_data.db') conn.text_factory = str cursor = conn.cursor() ins="insert into realData values (?,?,?,?,?,?,?,?)" content = "" if user.has_key("content"): content = user["content"] v = (id, content, user["userInfo"]["gender"], user["addTime"], user["userInfo"]["uname"], user["userInfo"]["uid"], user["id"], user["userInfo"]["uidType"]) cursor.execute(ins, v) cursor.close() conn.commit() conn.close() ## 轉換資料 if __name__ == '__main__': conn = sqlite3.connect('i_can_i_bb.db') conn.text_factory = str cursor = conn.cursor() cursor.execute("select * from originalData") values = cursor.fetchall() for item in values: saveRealItem(item[0], item[2]) cursor.close() conn.commit() conn.close()
- 分析資料
在海量的資料中,我們可以分析出我們想看到的結果。為了更好的資料處理和視覺化展示,筆者使用了 Pandas 和 Pyecharts 這兩個庫,很好用。
因愛奇藝使用者資料維度有限,所以只能簡單地分析性別。來綜合看一下,奇葩說使用者的男女比例。話不多說,先放程式碼:
conn = sqlite3.connect('deal_data.db') conn.text_factory = str data = pd.read_sql("select * from realData", conn) genderData = data.groupby(['gender']) rateDataCount = genderData["id"].agg([ "count"]) rateDataCount.reset_index(inplace=True) print rateDataCount attr = ["女", "男"] v1 = [rateDataCount["count"][i] for i in range(0, rateDataCount.shape[0])] pie = Pie("性別比例") pie.add("", attr, v1, is_label_show=True) pie.render("html/gender.html") conn.commit() conn.close()
使用 Pyecharts 畫了一個簡單的餅圖:
從圖中可以看出來,男女比例差不多到 1:2,看奇葩說的女性使用者,比男性使用者要多很多。也許,這也是這一季奇葩說情感話題比較多的一大原因。
接下來,我們再來看一下,每一期的評論數量,看是否能夠得出一些不一樣的資料。
還是先上程式碼:
conn = sqlite3.connect('deal_data.db') conn.text_factory = str data = pd.read_sql("select * from realData", conn) movieIdData = data.groupby(['movieId']) commentDataCount = movieIdData["movieId"].agg([ "count"]) commentDataCount.reset_index(inplace=True) print commentDataCount movies = { "1629260900":u"第 22 期", "1629256800":u"第 21 期", ## 後面的資料,這裡不列出來 } attr = [movies[commentDataCount["movieId"][i]] for i in range(0, commentDataCount.shape[0])] v1 = [commentDataCount["count"][i] for i in range(0, commentDataCount.shape[0])] bar = Bar("評論數量") bar.add("數量",attr,v1,is_stack=True,xaxis_rotate=30,yaxix_min=4.2, xaxis_interval=0,is_splitline_show=True,is_label_show=True) bar.render("html/comment_count.html") conn.commit() conn.close()
跑出來的資料如下:
從圖中的資料我們可以看到,評論數量並不會因為更新早而變得更多。所以可以看出,奇葩說的使用者群體是相對穩定的。不僅如此,我們也可以看出,在第 17 期評論數量比其他都要多,很有可能是這一期節目的話題更讓使用者關注。
分析了上面的兩個資料,下面再分析一下評論時間分佈,本次分析是按照星期來分析的,所以,還需要對資料進行一定的處理。將每一條評論所在星期更新到資料庫中,程式碼如下:
conn = sqlite3.connect('deal_data.db') conn.text_factory = str cursor = conn.cursor() cursor.execute("select * from realData") values = cursor.fetchall() cursor.close() for item in values: realTime = time.localtime(float(item[3])) realTime = time.strftime("%A",realTime) sql = "UPDATE `realData` SET `week`=\"" + realTime + "\" WHERE `id`=\"" + item[0] + "\"" cc = conn.cursor() cc.execute(sql) cc.close() conn.commit() conn.close() time.localtime()
使用折線圖分析如下:
conn = sqlite3.connect('deal_data.db') conn.text_factory = str data = pd.read_sql("select * from realData", conn) movieIdData = data.groupby(['week']) commentDataCount = movieIdData["week"].agg([ "count"]) commentDataCount.reset_index(inplace=True) print commentDataCount weekInfo = { "Monday":u"週一", "Tuesday":u"週二", "Wednesday":u"週三", "Thursday":u"週四", "Friday":u"週五", "Saturday":u"週六", "Sunday":u"週日" } weeks = [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday","Sunday" ] attr = [] v1 = [] week_temp = [commentDataCount["week"][i] for i in range(0, commentDataCount.shape[0])] for item in weeks: attr.append(weekInfo[item]) index = week_temp.index(item) v1.append(commentDataCount["count"][index]) bar = Line("天評論數量") bar.add("數量",attr,v1,is_stack=True,xaxis_rotate=30,yaxix_min=4.2, xaxis_interval=0,is_splitline_show=True,is_label_show=True) bar.render("html/comment_week_count.html")
可以看出,奇葩說的忠實使用者基本是在更新當天就看,並且週五、週六、週日的評論數量遠大於其他天。其實我們還可以分析,更新當天的 4 個小時內評論量有多大,感興趣的讀者可以嘗試去跑一下資料。
而作為一名程式設計師,筆者平時基本是不寫評論的,在這裡,我們特地分析了一下評論字數的分佈,不看不知道,一看嚇一跳。先上程式碼:
# 先獲取評論長度,並更新到資料庫中 conn = sqlite3.connect('deal_data.db') conn.text_factory = str cursor = conn.cursor() cursor.execute("select * from realData") values = cursor.fetchall() cursor.close() for item in values: content = item[1] length = 0 if len(content) <= 20: length = 0 elif len(content) > 20 and len(content) <= 50: length = 1 elif len(content) > 50 and len(content) <= 100: length = 2 else: length = 3 sql = "UPDATE `realData` SET `length`=\"" + str(length) + "\" WHERE `id`=\"" + item[0] + "\"" cc = conn.cursor() cc.execute(sql) cc.close() conn.commit() conn.close() time.localtime() # 獲取數量並展示 conn = sqlite3.connect('deal_data.db') conn.text_factory = str data = pd.read_sql("select * from realData", conn) lengthData = data.groupby(['length']) lengthDataCount = lengthData["movieId"].agg([ "count"]) lengthDataCount.reset_index(inplace=True) print lengthDataCount attr = ["20 字以內", "20~50 字", "50~100 字", "100 字以上"] v1 = [lengthDataCount["count"][i] for i in range(0, lengthDataCount.shape[0])] bar = Line("評論字數") bar.add("數量",attr,v1,is_stack=True,xaxis_rotate=30,yaxix_min=4.2, xaxis_interval=0,is_splitline_show=True,is_label_show=True) bar.render("html/comment_word_count.html") conn.commit() conn.close()
分析結果如下:
實在是沒有想到,100 字以上的評論居然有 1/4,在這個移動端已成視訊播放主要平臺的時代,使用者還能夠花費較多精力寫下評論,筆者還是比較震驚的。
最後,筆者將通過 jieba 把評論進行分詞,然後再以 wordcloud 製作詞雲來看看,觀眾朋友的整體評價:
conn = sqlite3.connect('deal_data.db') conn.text_factory = str data = pd.read_sql("select * from realData", conn) jieba.add_word("馬薇薇", freq = 20000, tag = None) comment = jieba.cut(str(data["content"]),cut_all=False) wl_space_split = " ".join(comment) backgroudImage = np.array(Image.open(r"./qipashuo.jpg")) stopword = STOPWORDS.copy() wc = WordCloud(width=1920,height=1080,background_color='white', mask=backgroudImage, font_path="/Users/zhaocheng/Documents/Deng.ttf", stopwords=stopword,max_font_size=400, random_state=50) wc.generate_from_text(wl_space_split) plt.imshow(wc) plt.axis("off") wc.to_file('html/word_cloud.png') conn.commit() conn.close()
詞雲圖:
通過上面的詞雲可以很明顯地看出,李誕、(薛)教授、(詹)青雲、馬薇薇、(傅)首爾等人物名稱高頻地出現在了評論裡面,他們才是這部綜藝的焦點人物。
歡迎關注我的公眾號,一起交流技術事。