Python步步飛升之爬取豆瓣電影短評(píng)告訴你《白蛇:緣起》為啥這么熱
1. 前言
一直喜歡動(dòng)畫(huà)電影,國(guó)內(nèi)國(guó)外都看了不少忌卤。很讓人欣慰的是妖异,國(guó)產(chǎn)動(dòng)畫(huà)大電影已經(jīng)長(zhǎng)進(jìn)不少,《魁拔》系列邀杏,《大圣歸來(lái)》贫奠,《大護(hù)法》等都讓我眼前一亮,最近正在上映的《白蛇:緣起》為追光動(dòng)畫(huà)出品望蜡,之前該公司的《小門(mén)神》就讓我高興的緊唤崭。在觀影之前先看豆瓣評(píng)論以避深坑已經(jīng)成為習(xí)慣,加之最近詞圖分析也很有意思脖律,作此文拋磚引玉谢肾。
2. 大概思路
- 用BeautifulSoup從豆瓣電影上爬取短評(píng)保存文件中
- 從文件中找出評(píng)論內(nèi)容用jieba分詞
- 用在線可視化工具wordart生成熱詞圖片
3. 從豆瓣電影上爬取短評(píng)
3.1 豆瓣網(wǎng)站爬蟲(chóng)限制
- 多次嘗試之后發(fā)現(xiàn),不登錄的情況下状您,只能查詢(xún)到200條短評(píng)
- 登錄之后也只能查看500條短評(píng)
- 從豆瓣網(wǎng)站robots.txt知道網(wǎng)站期望的被訪問(wèn)的間隔為5s
# Crawl-delay: 5
3.2 分析URL
剛開(kāi)始進(jìn)入短評(píng)url如下
https://movie.douban.com/subject/30331149/comments?start=0&limit=20&sort=new_score&status=P
查看源碼搜索"后頁(yè)"
<div id="paginator" class="center">
<span class="first"><< 首頁(yè)</span>
<span class="prev">< 前頁(yè)</span>
<a href="?start=20&limit=20&sort=new_score&status=P&percent_type=" data-page="" class="next">后頁(yè) ></a>
</div>
可以看到源碼后頁(yè)元素中有“start=20”勒叠,代碼中獲取這個(gè)start用以生成下一頁(yè)待爬取url兜挨。
點(diǎn)擊最下方“后頁(yè)”按鈕,新頁(yè)面url如下
https://movie.douban.com/subject/30331149/comments?start=20&limit=20&sort=new_score&status=P
其中眯分,30331149為《白蛇:緣起》電影id拌汇。每次下一頁(yè)后,start+20弊决,每頁(yè)限制為20條數(shù)據(jù)噪舀。
因douban限制,短評(píng)最多能查看500條數(shù)據(jù)飘诗,所以進(jìn)入url
https://movie.douban.com/subject/30331149/comments?start=480&limit=20&sort=new_score&status=P
之后發(fā)現(xiàn)“后頁(yè)”按鈕灰掉与倡,已經(jīng)不能再往下翻頁(yè)了。
查看源碼搜索"后頁(yè)"
<div id="paginator" class="center">
<a href="?start=0&limit=20&sort=new_score&status=P&percent_type=" data-page="1"><< 首頁(yè)</a>
<a href="?start=479&limit=-20&sort=new_score&status=P&percent_type=" data-page="">< 前頁(yè)</a>
<span class="next">后頁(yè) ></span>
</div>
發(fā)現(xiàn)后頁(yè)元素中start不存在昆稿,所以爬取的時(shí)候可以這點(diǎn)來(lái)判斷是否結(jié)束爬取纺座。
each = 0
while 1:
url = 'https://movie.douban.com/subject/' + \
self._movieId+'/comments?start=' + str(each) + \
'&limit=20&sort=new_score&status=P'
urlInfo = requests.get(
url, cookies=self._cookies, headers=self._headers)
print("從URL(%s)抓取評(píng)論中..." % urlInfo.url,)
nextPage = self.crawlOnePage(urlInfo.text)
# 沒(méi)有下一頁(yè),最后一個(gè)元素為前頁(yè)
if int(nextPage[-1]) < each:
print('抓取結(jié)束...')
break
else:
time.sleep(round(random.uniform(5.0, 5.5), 2)) ## 隨機(jī)暫停5-5.5s時(shí)間再發(fā)起請(qǐng)求
each = int(nextPage[-1])
3.3 cookie模擬登錄
最簡(jiǎn)單的方式就是在網(wǎng)站上登錄之后溉潭,Chrome中“F12”快捷鍵點(diǎn)開(kāi)調(diào)試工具净响,查看網(wǎng)絡(luò)隨意選取一個(gè)請(qǐng)求,記住header中cookie信息喳瓣,爬取數(shù)據(jù)時(shí)添加到請(qǐng)求header馋贤。
用requests發(fā)送請(qǐng)求時(shí),帶上cookie就好
self._cookies = {'cookie': cookie}
urlInfo = requests.get(url, cookies=self._cookies, headers=self._headers)
3.4 分析評(píng)論頁(yè)源碼獲取指定信息
查看一個(gè)評(píng)論頁(yè)面的源代碼
可見(jiàn)畏陕,
- 評(píng)論放在一個(gè)div中配乓,id="comments"
- 每個(gè)評(píng)論都在一個(gè)div中,class="comment-item"
- 評(píng)論人名稱(chēng)在一個(gè)鏈接中惠毁,當(dāng)href有值且鏈接中包含“people”元素犹芹,存在用戶(hù)已注銷(xiāo)情況
- 評(píng)論時(shí)間在一個(gè)span中,class="comment-time "
- 評(píng)論內(nèi)容在一個(gè)span中仁讨,class="short"
- 評(píng)論打星在一個(gè)span中羽莺,class="rating",存在未打分情況
- 投票在一個(gè)span中洞豁,class="votes"
用BS可以輕松提取這些數(shù)據(jù)盐固,代碼如下
def crawlOnePage(self, html):
soup = BeautifulSoup(html, 'lxml')
# 獲取電影名稱(chēng)
if self._movieName == '':
self._movieName = soup.select(
'.movie-summary')[0].find_all('img')[0]['title']
for item in soup.select('.comment'):
comment = {}
# 評(píng)論者
for a in item.find_all('a'):
if 'people' in a['href']:
comment['user'] = a.string
# 日期
comment['date'] = item.select('.comment-time')[0].string.strip()
# 內(nèi)容
comment['content'] = item.select('.short')[0].string
# 評(píng)價(jià)
try:
comment['eval'] = item.select('.rating')[0]['title']
# stars
comment['star'] = item.select('.rating')[0]['class'][0][-2]
except Exception:
# 存在用戶(hù)沒(méi)有打星情況
# print(str(item).encode('GBK', 'ignore').decode('GBk'))
comment['eval'] = '未打星'
comment['star'] = '-1'
# votes
comment['votes'] = item.select('.votes')[0].string
self._comments.append(comment)
pages = re.findall(r'href="\?start=(\d+)&.+"',
str(soup.select('#paginator')))
return pages
4. 獲取到的評(píng)論數(shù)據(jù)保存在csv中
使用csv模塊可以很方便的保存文件
fileName = self._movieName + '.csv'
with open(fileName, 'w', encoding='utf-8-sig', newline='') as csvfile:
fieldnames = ['user', 'date', 'eval', 'star', 'votes', 'content'] ## header
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
[writer.writerow(comment) for comment in self._comments] ## save comments line by line
5. 評(píng)論內(nèi)容分詞
下載“中文停用詞表.txt”,也可以在網(wǎng)上搜索相應(yīng)資源
使用jieba分詞取最熱100詞丈挟,并保存結(jié)果在文件中
def fenci(self):
print('開(kāi)始分詞...')
fenciFileName = os.path.join(
sys.path[0], self._movieName + '_分詞結(jié)果.csv')
CommentRecord = namedtuple(
'CommentRecord', ['user', 'date', 'eval', 'star', 'votes', 'content'])
analyse.set_stop_words(os.path.join(sys.path[0], '中文停用詞表.txt'))
content = []
csvName = os.path.join(sys.path[0], self._movieName + '.csv')
for emp in map(CommentRecord._make, csv.reader(open(csvName, mode='r', encoding='utf-8-sig'))):
content.append(emp.content)
tags = analyse.extract_tags(
' '.join(content), topK=100, withWeight=True)
with open(fenciFileName, 'w', encoding='utf-8-sig', newline='') as csvfile:
writer = csv.writer(csvfile)
[writer.writerow(item[0] + '\t' + str(int(item[1] * 1000)))
for item in tags]
print('分詞結(jié)束刁卜,保存結(jié)果在"%s"中...' % fenciFileName)
6. 用在線可視化工具wordart生成熱詞圖片
網(wǎng)站地址在此wordart
6.1 導(dǎo)入生成的詞匯
打開(kāi)“白蛇:緣起_分詞結(jié)果.csv”,復(fù)制兩列所有數(shù)據(jù)曙咽。
如圖蛔趴,在網(wǎng)站中一次點(diǎn)擊“WORDS”,“Import”例朱,選中“CSV Fromat”選項(xiàng)孝情,粘貼到文本框中鱼蝉,點(diǎn)擊“Import Words”按鈕。
6.2 選擇SHAPES
這里就是選擇形狀圖用來(lái)做背景箫荡,也可以自行上傳圖像文件
6.3 選擇FONTS
網(wǎng)站本身不支持中文魁亦,需要上傳一個(gè)中文字體,不然顯示出來(lái)都是框框羔挡。這里我上傳了NotoSansMonoCJKsc-Regular.otf用以顯示洁奈。然后點(diǎn)擊“Visualize”按鈕即可生成詞圖。
6.4 生成的詞圖
7. 結(jié)語(yǔ)
如有疑問(wèn)绞灼,歡迎留言共同探討利术。