本文介绍利用python爬取豆瓣电影的影片短评,并生成词云和统计数据
github地址:/736755244/douban_py
1、基本配置环境
版本:Python3.7
系统:Windows
2、所需模块及作用
以下模块如果没有安装,可以在cmd命令提示符里进行pip install + 模块名进行安装。
(PS:或者使用清华镜像,速度较快:pip install 模块名-i https://pypi.tuna./simple)
import requests # 处理网络请求from bs4 import BeautifulSoup #将HTML转换成树形结构import time # 时间模块import random # 随机数import pandas as pd # 数据分析包import xlsxwriter # excel相关from urllib.parse import quote # 编码import jieba # 词云相关from wordcloud import WordCloud # 词云import matplotlib.pyplot as plt # matplotlib.pyplot
PS:安装完wordcloud模块后,中文生成词云会乱码,需要做如下修改:
①方法一:使用的时候指定使用的文字字体
wordcloud.WordCloud(font_path='simhei.ttf').generate(xxx) # 使用微软雅黑字体
②方法二:直接修改模块引用,彻底解决这个问题
将自己的字体库放在安装目录中,并修改wordcloud.py文件中的引用
词频统计所需要的词语文件,可从搜狗词库中下载(.scel文件),然后格式转为txt文件
搜狗词库地址:/dict/
格式转换地址:/sceltotxt/
3、主要思路
①用户输入想搜索的电影名称
②对电影名称进行编码,并发送请求
③获取电影列表并打印,用户选择想要爬取的电影
④获取电影编号后,发送请求爬取页面
⑤对HTML页面进行处理,获取评论信息
⑥写入csv文件或excel文件
⑦生成词云图
⑧生成词频统计文件
4、代码相关
①获取影片列表接口:
在搜索栏输入名称时,发现会调用这个接口/j/subject_suggest?q=编码后的电影名称
②获取评论接口:
点击分页发现会调用这个接口:
/subject/'+ 影片id + '/reviews?start=(page+1)*10
或者这个接口:
/subject/' + 影片id + '/comments?start={' + page+1 + '}&limit=20&sort=new_score&status=P
数据准备:
# 浏览器代理头user_agent = ['Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.168 Safari/537.36','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1','Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/0101 Firefox/6.0','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50','Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50','Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3)','Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)','Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)','Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)','Mozilla/5.0 (Windows; U; Windows NT 6.1; ) AppleWebKit/534.12 (KHTML, like Gecko) Maxthon/3.0 Safari/534.12','Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)','Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.33 Safari/534.3 SE 2.X MetaSr 1.0','Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)','Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 QQBrowser/6.9.11079.201','Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E) QQBrowser/6.9.11079.201','Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36','Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/0101 Firefox/34.0','Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:70.0) Gecko/0101 Firefox/70.0']cok='bid=IvV3BPXNahg; _pk_id.100001.4cf6=ce978a8d138f1315.1575613176.3.1575785754.1575621036.; __utma=30149280.1347665870.1575613177.1575621033.1575785749.3; __utmz=30149280.1575613177.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=223695111.1029442254.1575613177.1575621033.1575785755.3; __utmz=223695111.1575785755.3.2.utmcsr=|utmccn=(referral)|utmcmd=referral|utmcct=/; ll="118159"; __utmb=30149280.2.10.1575785749; __utmc=30149280; __utmt=1; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1575785754%2C%22https%3A%2F%%2F%22%5D; _pk_ses.100001.4cf6=*; __utmb=223695111.0.10.1575785755; __utmc=223695111; ap_v=0,6.0; __yadk_uid=zHCYWt7NZH2tQi08F9GyUw1256zStXSG; _vwo_uuid_v2=DC415C5465AFD4240435B780F3852697D|7092204f7d5cfc68e89ef8843ed4212b'# 随机选取用户代理def get_ua():au = random.choice(user_agent)return au
①主程序入口:
# 主程序入口def main():movie_name = input("请输入想搜索的电影名称:")searchkey = quote(movie_name, 'utf-8')MovieUrl='/j/subject_suggest?q=%s'%searchkeyMovieList = get_movie(MovieUrl) # 获取相关电影列表if len(MovieList)>0:# 输出电影信息,供用户自己选择for i,v in enumerate(MovieList,1):print('影片编号:%d 影片名称:%s 影片上映时间:%s'%(i, v['title'], v['year']))input_mid = input('请输入想查看的影片编号:') # 选择电影mid = MovieList[int(input_mid)-1]['id'] # 获取电影编号pq_num = int(input('爬取多少页数据?')) # 输入爬取页数choose_movie(movie_name,mid,pq_num) # 爬取else:print('未获取到搜索结果')return
② 获取电影列表信息
# 抓取电影列表信息def get_movie(url):headers = {'User-Agent': get_ua(),'Host': '','Connection': 'keep-alive','Cookie':cok}res = requests.get(url, headers=headers)movie_list = res.json()if len(movie_list)>0:return movie_listelse:return []
③获取电影信息并解析
# 选择抓取的影片def choose_movie(movie_name,movie_id,pq_num):url = '/subject/' + movie_id + '/comments?start={}&limit=20&sort=new_score&status=P'comments = []print("开始爬取")start_time = time.time()for i in range(pq_num):print("*******开始爬取第%d页数据*******" % (i + 1))soup = get_soup(url.format(i * 20)) # 获取htmlcomments.extend(getText(soup)) # 添加列表中print("*******爬取完成,随机等待0-5秒*******")time.sleep(random.random() * 5)end_time = time.time()print("共用时%d秒" % (end_time - start_time))# 写入excel# writetoexcel(comments,movie_name)# 写入csvwritetocsv(movie_name, comments)# 抓取解析网页def get_soup(url):# 伪装浏览器发送请求headers = {'User-Agent': get_ua(),'Host': '','Connection': 'keep-alive','Cookie':cok}res = requests.get(url, headers=headers)# if res.status_code==200:#print("请求成功")time.sleep(random.random() * 5) # 设置时间间隔,防止太快被封res.encoding = 'utf-8'soup = BeautifulSoup(res.text, 'html.parser')print("解析完成")return soup# 获取一页用户的评论def getText(soup):comment_list = []for p in soup.select('.comment-item'):comment = {}# 根据元素选择器,获得所需的信息:用户名/评价/时间等username = p.select('.comment-info')[0]('a')[0].textwatch = p.select('.comment-info')[0]('span')[0].textintro = p.select('.comment-info')[0]('span')[1]['title']cTime = p.select('.comment-time ')[0]['title']pNum = p.select('.votes')[0].textshort = p.select('.short')[0].text.replace('\n', ' ')comment['用户名'] = usernamecomment['观看情况'] = watchcomment['评分推荐'] = introcomment['评论时间'] = cTimecomment['短评内容'] = shortcomment['赞同该评论次数'] = pNumcomment_list.append(comment)# comment_list.append([username,watch,intro,cTime,short,pNum])return comment_list
④写入excel文件或csv文件
# 写入exceldef writetoexcel(list,name):print('创建excel')book = xlsxwriter.Workbook(u'海王评论.xlsx')sheet = book.add_worksheet()sheet.write(0, 0, '用户名')sheet.write(0, 1, '观看情况')sheet.write(0, 2, '评分推荐')sheet.write(0, 3, '评论时间')sheet.write(0, 4, '短评内容')sheet.write(0, 5, '赞同该评论次数')row = 1col = 0for index, item in enumerate(list):# print('写入第%s行数据'%row)sheet.write(row, col, item[0]) # 用户名sheet.write(row, col + 1, item[1]) # 观看情况sheet.write(row, col + 2, item[2]) # 评分推荐sheet.write(row, col + 3, item[3]) # 评论时间sheet.write(row, col + 4, item[4]) # 短评内容sheet.write(row, col + 5, item[5]) # 赞同该评论次数row += 1print('写入完成')book.close() # 关闭# 是否生成词云time.sleep(3)isCleanData = input('是否生成词云(Y/N)?')if isCleanData == 'Y':get_text(name)# 写入csvdef writetocsv(name,list):commentFile = pd.DataFrame(list)commentFile.to_csv(r'%s.csv'%name, encoding='utf_8_sig')# 是否生成词云time.sleep(3)isCleanData=input('是否生成词云(Y/N)?')if isCleanData=='Y':get_text(name)
⑤生成词云和统计数据
# 生成词云和统计数据def get_text(name):# 读取爬取的评论fp = open(r'%s.csv'%name, 'r', encoding='utf-8').read()jieba.load_userdict('scel_to_text.txt')# jieba.add_word() # 可以添加自定义词典# 将文件中所有文字分词words_list = jieba.lcut(fp)# 用空格分隔词语tokenstr = ' '.join(words_list)mywc1 = WordCloud().generate(tokenstr)# 显示词云plt.imshow(mywc1)plt.axis('off')plt.show()mywc1.to_file('%s.png'%name) # 生成词云图片# 是否生成词频统计time.sleep(3)issum = input('是否生成词频统计(Y/N)?')if issum == 'Y':word_dict = {}# set:无序非重对象words_set = set(words_list)for w in words_set:# 高频词大于一个字的,当然这里可以自定义取值规则if len(w) > 1:word_dict[w] = words_list.count(w)# 排序 word_dict.items() : [('尤其', 1), ('雷神', 2), ('再现', 1), ('之子', 1), ('热泪盈眶', 1), ('不过', 3), ('记住', 1)]'''sorted:iterable -- 可迭代对象。cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。'''words_sort = sorted(word_dict.items(), key=lambda x: x[1], reverse=True)# 输出词频TOP20words_sort1 = words_sort[:20]pd.DataFrame(data=words_sort1).to_csv('统计数据.csv', encoding='utf-8')
5、运行结果
相关问题欢迎留言讨论!