代碼主要參考鏈接:segmentfault.com/a/1190

主要內容:使用的python版本是3.6.

  • 抓取網頁數據
  • 清理數據
  • 用詞雲進行展示

一.抓取網頁數據:

第一步要對網頁進行訪問,python中使用的是urllib庫。代碼如下:

from urllib import request
resp = request.urlopen(https://movie.douban.com/cinema/nowplaying/xian/)
html_data = resp.read().decode(utf-8)
print(html_data)
結果如下:
D:applicationAnaconda3python.exe F:/test/venv/pachong_learning.py
<!DOCTYPE html>
<html lang="zh-cmn-Hans" class="">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="renderer" content="webkit">
<meta name="referrer" content="always">
<meta name="google-site-verification" content="ok0wCgT20tBBgo9_zat2iAcimtN4Ftf5ccsh092Xeyw" />
<title>
豆瓣電影

其中movie.douban.com/是豆瓣最新上映的電影頁面,可以在瀏覽器中輸入該網址進行查看。html_data是字元串類型的變數,裡面存放了網頁的html代碼。

第二步,需要對得到的html代碼進行解析,得到裡面提取我們需要的數據。

在python中使用BeautifulSoup庫進行html代碼的解析。

BeautifulSoup使用的格式如下:

BeautifulSoup(html,"html.parser")

第一個參數為需要提取數據的html,第二個參數是指定解析器,然後使用find_all()讀取html標籤中的內容。

但是html中有這麼多的標籤,該讀取哪些標籤呢?其實,最簡單的辦法是我們可以打開我們爬取網頁的html代碼,然後查看我們需要的數據在哪個html標籤裡面,再進行讀取就可以了。如下圖所示:

從上圖中可以看出在div id="nowplaying"標籤開始是我們想要的數據,裡面有電影的名稱、評分、主演等信息。所以相應的代碼編寫如下:
from urllib import request
resp = request.urlopen(https://movie.douban.com/cinema/nowplaying/xian/)
html_data = resp.read().decode(utf-8)
from bs4 import BeautifulSoup as bs
soup = bs(html_data, html.parser)
nowplaying_movie = soup.find_all(div, id=nowplaying)
nowplaying_movie_list = nowplaying_movie[0].find_all(li, class_=list-item)
print(nowplaying_movie_list)
結果如下:
[<li class="list-item" data-actors="周潤發 / 郭富城 / 張靜初" data-category="nowplaying" data-director="庄文強" data-duration="130分鐘" data-enough="True" data-region="中國大陸 香港" data-release="2018" data-score="8.1" data-showed="True" data-star="40" data-subject="26425063" data-title="無雙" data-votecount="194137" id="26425063">
<ul class="">
<li class="poster">
<a class="ticket-btn" data-psource="poster" href="https://movie.douban.com/subject/26425063/?from=playing_poster" target="_blank">
<img alt="無雙" class="" rel="nofollow" src="//i1.wp.com/img3.doubanio.com/view/photo/s_ratio_poster/public/p2535096871.jpg"/>
</a>
</li>
<li class="stitle">
<a class="ticket-btn" data-psource="title" href="https://movie.douban.com/subject/26425063/?from=playing_poster" target="_blank" title="無雙">
無雙
</a>
</li>
<li class="srating">
<span class="rating-star allstar40"></span>
<span class="subject-rate">8.1</span>
</li>

在上圖中可以看到data-subject屬性裡面放了電影的id號碼,而在img標籤的alt屬性裡面放了電影的名字,因此我們就通過這兩個屬性來得到電影的id和名稱。(註:打開電影短評的網頁時需要用到電影的id,所以需要對它進行解析),編寫代碼如下:

nowplaying_list = []
for item in nowplaying_movie_list:
nowplaying_dict = {}
nowplaying_dict[id] = item[data-subject]
for tag_img_item in item.find_all(img):
nowplaying_dict[name] = tag_img_item[alt]
nowplaying_list.append(nowplaying_dict)
print(nowplaying_list)
結果如下:
[{id: 26425063, name: 無雙}, {id: 27140071, name: 找到你}, {id: 4864908, name: 影}, {id: 30140571, name: 嗝嗝老師}, {id: 27092785, name: 李茶的姑媽}, {id: 27102569, name: 悲傷逆流成河}, {id: 27149818, name: 胖子行動隊}, {id: 26649627, name: 超能泰坦}, {id: 30208004, name: 阿凡提之奇緣歷險}, {id: 26794854, name: 帝企鵝日記2:召喚}]

可以看到和豆瓣網址上面是匹配的。這樣就得到了最新電影的信息了。接下來就要進行對最新電影短評進行分析了。例如《無雙》的短評網址為:movie.douban.com/subjec後一頁:movie.douban.com/subjec

例如《無雙》的短評網址為:https://movie.douban.com/subject/26425063/comments?status=P
後一頁:https://movie.douban.com/subject/26425063/comments?start=20&limit=20&sort=new_score&status=P
再後一頁:https://movie.douban.com/subject/26425063/comments?start=40&limit=20&sort=new_score&status=P
其中26425063就是電影的id,start=0表示評論的第0條評論。可以看到網址的變化。

接下來接對該網址進行解析了。打開上圖中的短評頁面的html代碼,我們發現關於評論的數據是在div標籤的comment屬性下面,如下圖所示:

因此對此標籤進行解析,代碼如下:

for a in range(1,10):
requrl=https://movie.douban.com/subject/26425063/comments?start={}&limit=20&sort=new_score&status=P.format(a*20)
resp = request.urlopen(requrl)
html_data = resp.read().decode(utf-8)
soup = bs(html_data, html.parser)
comment_div_lits = soup.find_all(div, class_=comment)
print(comment_div_lits)
結果如下:
<p class="">
<span class="short">這幾年很欣喜有《樹大招風》《追龍》,今年又有這部《無雙》,感謝這些導演還能找到初心,讓港片無法被取代。劇情終於不再是簡單的黑白對壘和人性光輝,主題線的豐富讓謊言戳穿的時候,留下最痛的紀念品。最後,重回槍林彈雨的發哥,你一定不能錯過。</span>

此時在comment_div_lits列表中存放的就是div標籤和comment屬性下面的html代碼了。在上圖中還可以發現在p標籤下面存放了網友對電影的評論,如下圖所示:

因此對comment_div_lits代碼中的html代碼繼續進行解析,代碼如下:

eachCommentList = [];
for item in comment_div_lits:
if item.find_all(p)is not None:
eachCommentList.append(item.find_all(p))
print(eachCommentList)
結果如下:
<span class="short">我數次以為周潤發和郭富城會親下去...</span>
</p>], [<p class="">
<span class="short">失望,後面的反轉什麼玩意兒,是劇情圓不過來了嗎?現在都電子支付,假鈔這玩意兒,還有多大的生存空間,脫離的現實,港片落幕</span>
</p>], [<p class="">
<span class="short">《無雙》是一部有智商的電影,好久沒見這麼講究的港片了,庄文強回到他擅長的一波三折的路線,郭富城飾演這個角色很顛覆,華語電影里比較少見,具有非常精巧的隱蔽性,看似人畜無害實際上可能運籌帷幄,這幾年演慣喜劇的發哥在正劇里也氣場強大,不遑多讓。你看到假鈔可能是真鈔,你看到名畫可能是假畫,你身邊的愛人可能是假愛人,演員沒有人格分裂,觀眾要看得人格分裂了,眼前的一切還有什麼是真的嗎?最後一刻見真相。</span>
</p>], [<p class="">
<span class="short">超出預期,應該是國慶檔中最喜歡的一部,非常嫌疑犯版陽光燦爛的日子。說這是非常嫌疑犯玩剩下的老梗其實對庄文強挺不公平的,無雙里的反轉也許沒有非常嫌疑犯里那麼精緻和到位,但它是帶著主題表達的。</span>
</p>], [<p class="">
<span class="short">港片已經衰弱了 ,可以說是差不多死了</span>
</p>]]

二.清理數據

為了方便進行數據進行清洗,我們將列表中的數據放在一個字元串數組中,代碼如下:

comments =
for k in range(len(eachCommentList)):
comments = comments + (str(eachCommentList[k])).strip()
print(comments)
結果如下:
<span class="short">優雅又殘忍,發哥太迷人。</span>
</p>][<p class="">
<span class="short">一幫技術宅男跑去炸金三角基地,編劇你真敢想啊</span>
</p>][<p class="">
<span class="short">我數次以為周潤發和郭富城會親下去...</span>
</p>][<p class="">
<span class="short">失望,後面的反轉什麼玩意兒,是劇情圓不過來了嗎?現在都電子支付,假鈔這玩意兒,還有多大的生存空間,脫離的現實,港片落幕</span>
</p>][<p class="">
<span class="short">《無雙》是一部有智商的電影,好久沒見這麼講究的港片了,庄文強回到他擅長的一波三折的路線,郭富城飾演這個角色很顛覆,華語電影里比較少見,具有非常精巧的隱蔽性,看似人畜無害實際上可能運籌帷幄,這幾年演慣喜劇的發哥在正劇里也氣場強大,不遑多讓。你看到假鈔可能是真鈔,你看到名畫可能是假畫,你身邊的愛人可能是假愛人,演員沒有人格分裂,觀眾要看得人格分裂了,眼前的一切還有什麼是真的嗎?最後一刻見真相。</span>
</p>][<p class="">
<span class="short">超出預期,應該是國慶檔中最喜歡的一部,非常嫌疑犯版陽光燦爛的日子。說這是非常嫌疑犯玩剩下的老

可以看到所有的評論已經變成一個字元串了,但是我們發現評論中還有不少的標點符號等。這些符號對我們進行詞頻統計時根本沒有用,因此要將它們清除。所用的方法是正則表達式。python中正則表達式是通過re模塊來實現的。代碼如下:

import re

pattern = re.compile(r[u4e00-u9fa5]+)
filterdata = re.findall(pattern, eachCommentList)
cleaned_comments = .join(filterdata)
print(cleaned_comments)
結果如下:
這幾年很欣喜有樹大招風追龍今年又有這部無雙感謝這些導演還能找到初心讓港片無法被取代劇情終於不再是簡單的黑白對壘和人性光輝主題線的豐富讓謊言戳穿的時候留下最痛的紀念品最後重回槍林彈雨的發哥你一定不能錯過導演說拍這部電影是想讓現在的年輕人知道發哥意味著什麼還用問嘛意味著天下無雙的帥啊懷揣藝術匠心開創假鈔帝國的大亨乍聽有點像奧斯卡路數的梟雄傳記片影片整體那種復古質感也很好片中周潤發多次小馬哥附體顏值大長腿最重要的是又雅又痞風度翩翩一比這屆鮮肉真是弱爆了郭天王也很好玩這次演個慫包偽發哥和城城真是強攻弱受組合對話完全是個喜劇片當然兩位演技都很棒搞笑也能立住不垮看到最後又一切都能說通了也到最後才知道片名是什麼含義今年國慶檔三強無雙影李茶的姑媽居然都是講一個人的真假身份有趣美術系學生看了會沉默金融系學生看了會流淚發哥真的太太太太帥了我的價值就是作假今年國慶檔最佳偽鈔版戰爭之王莊文強擅長犯罪事件描述和正反角色衝突缺點是有些啰嗦故事太細生怕觀眾看不懂前半段偽鈔製作部分大開眼界後半段人性矛盾激化高智商人才卻選擇造假耐人尋味結尾大反轉借鑒了西方兩部著名作品但仍然精彩瞞天過海以假亂真演員都不錯發哥暴走段落致敬黃金時代的英雄片是這個真實的故事中浪漫的情懷之夢做為一名發哥死忠終於盼到發哥回歸港片表演上依然是瀟洒自如詼諧逗趣庄文強對故事和人物的打磨也保持一慣的品質這才是商業片應有的樣子首映紅毯蹲守到發哥了啊啊啊啊又名偽鈔製造教程從入門到入獄零基礎教學不限年齡不限學歷包學包會包就業還包坐牢你可以畫出最逼真的假畫可以製造最逼真的假鈔卻無法偽造你和阮文的關係你可以把秀清變成阮文的模樣卻無法讓阮文真正喜歡你你只顧著拚命賺錢從不和阮文說說話約約會至始至終未曾踏出半步而一次冒著生命危險的營救就讓秀清對你私定終身你看並不是沒有人喜歡你而是你從來沒有付出實際行動從來沒有讓她知道你喜歡她你對一面之緣的秀清做得太多卻對心心念念的阮文做得太少你以為有了錢就有了一切可她要的從來都不是巨額存款而是一句關心的問候一個溫暖的擁抱錢能買一棟酒店一艘遊艇但它買不到愛情假畫可以賣錢假鈔可以購物可是假的阮文終究不是你喜歡的那個人鈔票可以造假愛情不能造假如果不算最後的幾個轉前面完全就是愛情故事啊犯罪大佬悉心調教傻白甜窮畫家給買度假酒店給盡情發揮才華教他追前女友還幫忙弄死未婚夫寵溺程度直逼晉江小說酒店按頭那段簡直下一秒就要強吻了周潤發穿白西裝槍戰的一節巨巨巨巨巨帥無比看得我內心瘋狂尖叫還有一身黑色風衣三件套身材比例擊敗當代小鮮肉郭富城這個角色當個畫家太可惜了內心明明住了一個耽美寫手腦補出一整部兄貴養成文目測這是國慶檔最大贏家因為其它幾部太爛

我們可以看到此時評論數據中已經沒有那些標點符號了,數據變得「乾淨」了很多。

因此要進行詞頻統計,所以先要進行中文分詞操作。在這裡我使用的是結巴分詞。如果沒有安裝結巴分詞,可以在控制台使用pip install jieba進行安裝。(註:可以使用pip list查看是否安裝了這些庫)。代碼如下所示:

import jieba #分詞包
import pandas as pd

segment = jieba.lcut(cleaned_comments)
words_df=pd.DataFrame({segment:segment})
print(words_df.head())

因為結巴分詞要用到pandas,所以我們這裡載入了pandas包。可以使用words_df.head()

查看分詞之後的結果,如下圖所示:

segment
0 這
1 幾年
2 很
3 欣喜
4 有

一般有「看」、「太」、「的」等虛詞(停用詞),而這些詞在任何場景中都是高頻時,並且沒有實際的含義,所以我們要他們進行清除。

我把停用詞放在一個stopwords.txt文件中,將我們的數據與停用詞進行比對即可(註:只要在百度中輸入stopwords.txt,就可以下載到該文件)。去停用詞代碼如下代碼如下:

stopwords=pd.read_csv("stopwords.txt",index_col=False,quoting=3,sep=" ",names=[stopword], encoding=utf-8)#quoting=3全不引用
words_df=words_df[~words_df.segment.isin(stopwords.stopword)]

繼續使用words_df.head()語句來查看結果,如下圖所示,停用詞已經被出去了。

接下來就要進行詞頻統計了,代碼如下:

import numpy #numpy計算包
words_stat=words_df.groupby(by=[segment])[segment].agg({"計數":numpy.size})
words_stat=words_stat.reset_index().sort_values(by=["計數"],ascending=False)
用words_stat.head()進行查看,結果如下:
segment 計數
58 的 6
26 和 3
49 無雙 3
8 從 3
42 情感 2

由於我們前面只是爬取了第一頁的評論,所以數據有點少,在最後給出的完整代碼中,我爬取了10頁的評論,所數據還是有參考價值。

三.用詞雲進行展示(優於wordcloud沒有合適的版本所以不能顯示運行結果,抱歉)

代碼如下:

import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib
matplotlib.rcParams[figure.figsize] = (10.0, 5.0)
from wordcloud import WordCloud#詞雲包

wordcloud=WordCloud(font_path="simhei.ttf",background_color="white",max_font_size=80) #指定字體類型、字體大小和字體顏色
word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
word_frequence_list = []
for key in word_frequence:
temp = (key,word_frequence[key])
word_frequence_list.append(temp)

wordcloud=wordcloud.fit_words(word_frequence_list)
plt.imshow(wordcloud)

其中simhei.ttf使用來指定字體的,可以在百度上輸入simhei.ttf進行下載後,放入程序的根目錄即可。

完整的代碼:

from urllib import request
resp = request.urlopen(https://movie.douban.com/cinema/nowplaying/xian/)
html_data = resp.read().decode(utf-8)
from bs4 import BeautifulSoup as bs
soup = bs(html_data, html.parser)
nowplaying_movie = soup.find_all(div, id=nowplaying)
nowplaying_movie_list = nowplaying_movie[0].find_all(li, class_=list-item)
nowplaying_list = []
for item in nowplaying_movie_list:
nowplaying_dict = {}
nowplaying_dict[id] = item[data-subject]
for tag_img_item in item.find_all(img):
nowplaying_dict[name] = tag_img_item[alt]
nowplaying_list.append(nowplaying_dict)
#requrl=https://movie.douban.com/subject/ + nowplaying_list[0][id] + /comments +? +start=0 + &limit=20 +&sort=new_score+&status=P
for a in range(1,10):
requrl=https://movie.douban.com/subject/26425063/comments?start={}&limit=20&sort=new_score&status=P.format(a*20)
resp = request.urlopen(requrl)
html_data = resp.read().decode(utf-8)
soup = bs(html_data, html.parser)
comment_div_lits = soup.find_all(div, class_=comment)
eachCommentList = [];
for item in comment_div_lits:
if item.find_all(p) is not None:
eachCommentList.append(item.find_all(p))
comments =
for k in range(len(eachCommentList)):
comments = comments + (str(eachCommentList[k])).strip()
import re

pattern = re.compile(r[u4e00-u9fa5]+)
filterdata = re.findall(pattern, comments)
cleaned_comments = .join(filterdata)
import jieba # 分詞包
import pandas as pd
segment = jieba.lcut(cleaned_comments)
words_df = pd.DataFrame({segment: segment})
import numpy # numpy計算包

words_stat = words_df.groupby(by=[segment])[segment].agg({"計數": numpy.size})
words_stat = words_stat.reset_index().sort_values(by=["計數"], ascending=False)
print(words_stat.head())

推薦閱讀:

相关文章