最近学习了爬虫,结合wordcloud库,我们爬取电影评论,并分词绘制出该电影的画像。
话不多说
1、技术路线:(其中imageio是制作词云引用本地特殊图片作为词云图片的三方库)
import requests
from bs4 import BeautifulSoup
import jieba
import wordcloud
from imageio import imread
先看效果:
原图:
效果图:
2、绘制词云图片 draw()
创建变量comment保存爬取的所有评论,这里的comment是字符串,字符串内容通过allComment()函数实现,实现方式在第3条显示。
首先创建空字典D,利用jieba.lcut将字符串分词,并保存在字典D中(实现计频次功能)
创建的第二个字典d字典是为了将字典D中分词数量不足的键值对去除,if D[i] > 1:条件中更改数量1可自行去除分词数量低于多少的键值对。
用imread()实例化一个对象,用于加载自定义绘制的图片。
def draw():
# comment变量是所有评论,用allComment函数获取
comment = allComment()
# 创建字典D,用于分词并统计
D = {}
for word in jieba.lcut(comment):
if len(word) >= 2:
D[word] = D.get(word, 0) + 1
# 创建字典d,
d = {}
for i in D.keys():
if D[i] > 1:
d[i] = D[i]
mk = imread('自由.jpg')
image_colors = wordcloud.ImageColorGenerator(mk)
w = wordcloud.WordCloud(font_path='msyh.ttc', mask=mk, background_color='white',
color_func=image_colors)
w.generate_from_frequencies(d)
w.to_file('outfile.png')
3、爬取评论信息
getHtml()是固定用法,用于创建连接,返回网页源文,详细管理getHtml()的写法和原理可以参考我之前写的一篇文章"网络美女爬取",其中headers中cookie、referer、user-agent可在浏览器中查到,手动添加进来(1、打开URL后按F12 2、刷新 3、点击链接 4、点击标头 然后就可以看到这几个参数了)。
getComment()是获取单页的所有评论,传入getHtml()返回的网页信息,利用bs4库进行解析,提取,拼接正文
allComment()是将所有我们需求的爬取多少页的评论拼接,并返回一个文本信息,供draw()函数绘制词云,其中要说的是关于url的处理,这里观察评论页的url可以发现每页评论的url区别在于start参数不一致,每页20个评论,以此为倍数增加,运用了列表推导式,并用循环添加了后半部分,然后调用getHtml()、getComment()实现评论的爬取、解析、获取,最后返回的comment提供给draw()绘制词云。
def getHtml(url): #固定格式,获取html文件
headers = {
'cookie': '__utmv=30149280.14247; _vwo_uuid_v2=D3556343CE2E9E566DF0C05A58AF2A096|1d52e48c7db254bf3507b77fb1dd0501; douban-profile-remind=1; viewed="3354490"; gr_user_id=36a9716a-5535-4142-9f17-98e3be67d379; __gads=ID=74f8b061d649d634-22085b49d8c700ee:T=1620293559:RT=1620293559:R:S=ALNI_MZvBMW7P41O7IT9NEROcocj39LBdw; UM_distinctid=1794105a1162-0655bea5a2d0ba-3e604809-144000-1794105a11774; ll="118168"; bid=eprWYq_M_1M; __utma=30149280.352782848.1599137845.1625878048.1625886682.11; __utmc=30149280; __utmz=30149280.1625886682.11.6.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; ap_v=0,6.0; __utmb=30149280.2.10.1625886682',
'referer': 'https://movie.douban.com/subject/1292052/reviews?',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
try:
r = requests.get(url, headers = headers)
# 获取状态码,如果不是则200报错
r.raise_for_status()
# 修改编码为文本解析的编码格式
r.encoding = 'utf-8'
# 返回文本
return r.text
except:
print('网络状态错误')
def getComment(text):
soup = BeautifulSoup(text, 'html.parser')
ls = soup.find_all('span', class_="short")
comment = ''
for l in ls:
comment += l.string
return comment
def allComment():
# 观察网址,每页20条内容,在参数start体现,利用列表推导式罗列出需要的列表(前200条评论)
url = ['https://movie.douban.com/subject/1292052/comments?start=' + str(x) for x in range(0, 200, 20)]
comment = ''
for l in url:
l += '&limit=20&status=P&sort=new_score'
text = getHtml(l)
comment += getComment(text)
return comment
4、完整的代码
'''
主题:电影画像
作者:COS0度
时间:2021年7月10日
版本:1.0
'''
import requests
from bs4 import BeautifulSoup
import jieba
import wordcloud
from imageio import imread
def getHtml(url): #固定格式,获取html文件
headers = {
'cookie': '__utmv=30149280.14247; _vwo_uuid_v2=D3556343CE2E9E566DF0C05A58AF2A096|1d52e48c7db254bf3507b77fb1dd0501; douban-profile-remind=1; viewed="3354490"; gr_user_id=36a9716a-5535-4142-9f17-98e3be67d379; __gads=ID=74f8b061d649d634-22085b49d8c700ee:T=1620293559:RT=1620293559:R:S=ALNI_MZvBMW7P41O7IT9NEROcocj39LBdw; UM_distinctid=1794105a1162-0655bea5a2d0ba-3e604809-144000-1794105a11774; ll="118168"; bid=eprWYq_M_1M; __utma=30149280.352782848.1599137845.1625878048.1625886682.11; __utmc=30149280; __utmz=30149280.1625886682.11.6.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; ap_v=0,6.0; __utmb=30149280.2.10.1625886682',
'referer': 'https://movie.douban.com/subject/1292052/reviews?',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
try:
r = requests.get(url, headers = headers)
# 获取状态码,如果不是则200报错
r.raise_for_status()
# 修改编码为文本解析的编码格式
r.encoding = 'utf-8'
# 返回文本
return r.text
except:
print('网络状态错误')
def getComment(text):
soup = BeautifulSoup(text, 'html.parser')
ls = soup.find_all('span', class_="short")
comment = ''
for l in ls:
comment += l.string
return comment
def allComment():
# 观察网址,每页20条内容,在参数start体现,利用列表推导式罗列出需要的列表(前200条评论)
url = ['https://movie.douban.com/subject/1292052/comments?start=' + str(x) for x in range(0, 200, 20)]
comment = ''
for l in url:
l += '&limit=20&status=P&sort=new_score'
text = getHtml(l)
comment += getComment(text)
return comment
def draw():
# comment变量是所有评论,用allComment函数获取
comment = allComment()
# 创建字典D,用于分词并统计
D = {}
for word in jieba.lcut(comment):
if len(word) >= 2:
D[word] = D.get(word, 0) + 1
# 创建字典d,
d = {}
for i in D.keys():
if D[i] > 1:
d[i] = D[i]
mk = imread('自由.jpg')
image_colors = wordcloud.ImageColorGenerator(mk)
w = wordcloud.WordCloud(font_path='msyh.ttc', mask=mk, background_color='white',
color_func=image_colors)
w.generate_from_frequencies(d)
w.to_file('outfile.png')
if __name__ == '__main__':
draw()