查看原文
其他

爬虫实战丨走进哈利波特的魔法世界

爬虫俱乐部 Stata and Python数据分析 2022-03-15

本文作者:温和铭,中南财经政法大学统计与数学学院

本文编辑:张孟晗

技术总编:陈   鼎

Stata&Python云端课程来啦!

       为了感谢大家长久以来的支持和信任,爬虫俱乐部为大家送福利啦!!!Stata&Python特惠课程双双上线腾讯课堂~爬虫俱乐部推出了Python编程培训课程Stata基础课程Stata进阶课程Stata文本分析正则表达式网络爬虫基本字符串课程。报名课程即可加入答疑群,对报名有任何疑问欢迎在公众号后台和腾讯课堂留言哦。我们在这篇推文的最后提供了每门课程的课程二维码,大家有需要的话可以直接扫描二维码查看课程详情并进行购买哦~


引言

哈利波特这个IP一度风靡全球,今年九月,《哈利波特:魔法觉醒》手游的上线和北京环球影城的开园,为众多哈迷带来了一波又一波“回忆杀”。而对于那些只看过一遍小说或电影,甚至是对哈利波特仅仅只是听说过的“麻瓜”们,要想回忆或深入了解故事剧情却不太容易,毕竟,整个哈利波特系列共有七部小说和八部电影。如何快速走进哈利波特的魔法世界呢?爬虫“魔法”或许能助你一臂之力!
本次实战内容是:使用Xpath爬取哈利波特系列电影第一部《哈利·波特与魔法石》的豆瓣影评信息,并进行词频统计和绘制词云图。


一、爬取电影影评
首先我们点进电影的介绍页面,下滑点击“更多影评”选项,进入影评页面,观察影评的显示情况。

可以看到,影评页面中仅仅展示了每篇影评的前三行内容,需要点击标题跳转页面,才能获取完整的影评内容。此外,每页仅展示了20条影评,想要得到更多内容需要翻页。点击进入某一篇影评,可以看到我们想要爬取的页面信息,包括评论者、评分和完整影评。

由此我们可以确定爬取的大致流程为:翻页+模拟点击+提取页面信息。
1翻页

通过点击页码翻页,可以发现url的变化为:
第一页:
https://movie.douban.com/subject/1295038/reviews
第二页:
https://movie.douban.com/subject/1295038/reviews?start=20
第三页:
https://movie.douban.com/subject/1295038/reviews?start=40
不难看出,除了第一页,剩下的url中变化的只有参数start,推测第一页的start为0,于是尝试输入https://movie.douban.com/subject/1295038/reviews?start=0结果确实为第一页的内容:

至此,我们就确定了页码的变化规律,将每页的url放在一个列表里,使用for循环就能访问每一页的内容,达到自动翻页的效果:
# 访问前10页的影评页面(翻页)urls_page = list()for i in range(0, 10, 1): i *=20 url_page = "https://movie.douban.com/subject/1295038/reviews?start={}".format(i) urls_page.append(url_page)
2模拟点击
当我们实现自动翻页后,还需要点击每一页中每一篇影评的url才能进入真正需要爬取信息的页面,同样使用for循环,获取每页中所有影评页面的url,这里用的是影评标题对应的提取语句"//h2/a/@href":

#查看每页中的影评urls_movie = list()for url in urls_page: #获取页面中的所有影评页面的url response = requests.get(url, headers=headers) content = response.content.decode("utf-8") #解析HTML文档并提取所有影评页面的url html = etree.HTML(content) url_movie = html.xpath("//h2/a/@href") #Xpath定位影评标题 urls_movie.append(url_movie)
3提取页面信息
进入某一篇影评页,在检查页面,我们可以找到评论者、评分、评论内容的位置,由此编写Xpath提取语句。
1、提取评论者和评分

其中,评论者的提取比较简单,评分则是根据显示的星级提取对应的标签属性,即“力荐”。
2、提取剧透警告
豆瓣影评有一个特色就是包含“剧透警告”,通常是没看过电影的小伙伴们的“避雷”指示,但在这里,我们恰恰需要的就是这些含有剧透的影评,以便更快地了解剧情。

在这里我们根据上一级div标签中的class='main-bd'对剧透警告进行定位和提取。
3、提取影评内容

根据网页信息,不难看出完整影评和摘要都放在一个id='link-report'的div标签下,故只需以此标签为起始,选择下级的所有p标签即可,注意此处要使用双斜杠\\。

确定好了每一步爬取的具体策略,接下来就可以开始施展爬虫“魔法”了,完整的代码如下:

import requestsfrom lxml import etreeimport xlwtimport time
#设置请求头参数headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36' }#访问前10页的影评页面(翻页)urls_page = list()for i in range(0, 10, 1): i *=20 url_page = "https://movie.douban.com/subject/1295038/reviews?start={}".format(i) urls_page.append(url_page)#查看每页中的影评urls_movie = list()for url in urls_page: #获取页面中的所有影评页面的url response = requests.get(url, headers=headers) content = response.content.decode("utf-8") #解析HTML文档并提取所有影评页面的url html = etree.HTML(content) url_movie = html.xpath("//h2/a/@href") urls_movie.append(url_movie) movies = list()#i用于记录页数i = 0#urls_movie中的每一个元素都是一个列表,每个列表都表示一页中所有电影的影评urlfor page in urls_movie: for url in page: #对每一个url都进行一次爬虫操作 response_movie = requests.get(url, headers=headers) content = response_movie.content.decode("utf-8") html = etree.HTML(content) #电影评论者 commenter = html.xpath("//header/a/span/text()")[0] #评论者评分 rank = html.xpath("//header//span/@title") if not rank: rank = "无" else: rank = rank[0] #剧透警告 spoiler = html.xpath("//div[@class='main-bd']//p/text()") if not spoiler: spoiler = "无" else: spoiler = spoiler[0] # 影评及拼接 comment_list = html.xpath("//div[@id='link-report']//p/text()") comment = "".join(comment_list) movie = { "commenter": commenter, "rank": rank, "spoiler": spoiler, "comment": comment } movies.append(movie) i +=1 print("第{}页已经爬取完成".format(i)) time.sleep(1.5)print(len(movies)) #显示一共爬取了多少条影评# 存储为excelworkbook = xlwt.Workbook(encoding="utf-8")sheet1 = workbook.add_sheet("电影影评")keys = list(movies[0].keys())#表头for i in range(len(keys)): sheet1.write(0, i, keys[i]) #数据for row in range(1, len(movies)+1): for col, key in zip(range(len(keys)), keys): sheet1.write(row, col, movies[row - 1][key]) workbook.save(r"C:\Users\Desktop\哈利波特与魔法石影评.xls")
至此,我们已经实现了爬取电影前十页的影评信息,包括评论者、评分、剧透警告以及完整影评。


二、可视化分析
有了影评信息,接下来我们就可以进行可视化分析了。这里展示了频数直方图和词云图的绘制过程。
1评论者对电影的推荐程度情况
import xlrdimport collectionsfrom collections import Counterimport numpy as npimport matplotlib.pyplot as pltfrom pylab import mpl
#读取表格data=xlrd.open_workbook("哈利波特与魔法石影评.xls")#获取表格的sheetstable=data.sheets()[0]#获取第二列数据,即评分rankdata = table.col_values(1,start_rowx=1) #去掉第一行标签值counter = Counter(rankdata) #统计频数print(counter) #显示计数结果
#绘制频数分布直方图mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题plt.style.use("ggplot")x = ['无', '较差', '还行','推荐','力荐']y = [37, 2, 6, 42, 113]fig, ax = plt.subplots(figsize=(10, 7))ax.bar(x=x, height=y)ax.set_title("电影评分频数分布直方图", fontsize=15)

可以看出,大多数观众对电影给出了好评,说明作为系列电影的首打,《哈利·波特与魔法石》值得一看。
2绘制词云图

要想具体了解电影讲了什么故事,我们可以通过绘制词云图,对影评内容有个大致的了解。首先对爬取到的文件“哈利波特与魔法石影评.xls”进行一个预处理,主要步骤包括:①去除表格中的空格;②筛选出spoiler变量中含有“剧透警告”的影评;③提取表格中的影评内容,并另存为“剧透影评.txt”。由于篇幅有限,故不在此展示具体步骤,接下来,让我们快进到词频统计和绘制词云图的关键步骤:
#加载所需包import numpy as npimport pandas as pdimport jieba,codecsimport jieba.posseg as pseg #标注词性模块import matplotlib.pyplot as pltfrom wordcloud import WordCloudfrom imageio import imread #导入人名、停用词、特定词库renmings = pd.read_csv('人名.txt',engine='python',encoding='utf-8',names=['renming'])['renming']stopwords = pd.read_csv('stopword.txt',engine='python',encoding='utf-8',names=['stopwords'])['stopwords'].tolist()comment = open('剧透影评.txt',encoding='utf-8').read()jieba.load_userdict('哈利波特词库.txt') #定义一个分词函数def words_cut(comment): words = list(jieba.cut(comment)) stopwords1 = [w for w in words if len(w)==1] #添加停用词 seg = set(words) - set(stopwords) - set(stopwords1) #过滤停用词,得到更为精确的分词 result = [i for i in words if i in seg] return result #初次分词commentwords = words_cut(comment)renming = [i.split(' ')[0] for i in set(renmings)] #只要人物名字,出掉词频以及词性nameswords = [i for i in commentwords if i in set(renming)] #筛选出人物名字 #统计词频commentwords_count = pd.Series(commentwords).value_counts().sort_values(ascending=False)nameswords_count = pd.Series(nameswords).value_counts().sort_values(ascending=False)commentwords_count[:100].index
故事的核心是角色,故这里仅对人名进行了统计,用到了笔者自己整理的人名和哈利波特词库。

可以看出,初次分词结果不是十分理想,比如“哈利波特”被分成了“哈利波”,故我们添加一些自定义词,优化分词效果:
#自定义部分词语jieba.add_word('邓布利多',100,'nr')jieba.add_word('哈利波特',100,'nr')jieba.add_word('霍格沃茨',100,'n')jieba.add_word('拉唐克斯',100,'nr')jieba.add_word('伏地魔',100,'nr')jieba.del_word('罗恩说')jieba.del_word('地说')jieba.del_word('斯内') #再次分词commentwords = words_cut(comment)nameswords = [i for i in commentwords if i in set(renming)]commentwords_count = pd.Series(commentwords).value_counts().sort_values(ascending=False)nameswords_count = pd.Series(nameswords).value_counts().sort_values(ascending=False)commentwords_count[:100].index

再次分词的结果比较理想,基本上可以看出这部电影的大致脉络,故事主要围绕着哈利波特和伏地魔之间的斗争展开,主要人物有罗恩、赫敏、海格和邓布利多等人。接下来我们绘制词云:
#绘制词云#读取背景图片back_picture = imread("cloud.jpg")#设置词云参数wc = WordCloud(font_path="simhei.ttf", background_color="black", max_words=2000, mask=back_picture, max_font_size=200, random_state=42 )wc2 = wc.fit_words(commentwords_count)#绘制词云图plt.figure(figsize=(20,10))plt.imshow(wc2)plt.axis("off")plt.show()wc.to_file("ciyun.png")

词云一出,主角和小伙伴们的出现频次就一览无余了,我们对电影的剧情和人物也有了一个基本概念,终于不再只是徘徊在魔法世界以外的“麻瓜”啦~感兴趣的小伙伴可以后台回复“哈利波特”获取完整代码和数据文件。



RECOMMEND

最后,我们为大家揭秘雪球网(https://xueqiu.com/)最新所展示的沪深证券和港股关注人数增长Top10。



腾讯课堂课程二维码








            


 对我们的推文累计打赏超过1000元,我们即可给您开具发票,发票类别为“咨询费”。用心做事,不负您的支持!











往期推文推荐

        数据集合并的新路子-frlink命令

        Seminar丨附近的公司:利用卫星图像研究本地信息优势

        线性同余法生成伪随机数 

         [技能篇]多线程爬虫

“好哭”是衡量一部好电影的标准吗?

Stata&Python云端课程来啦!

带你了解Stata中的矩阵

Seminar|总统的朋友:政治关联与企业价值
爬虫实战 | 爬取中国天气网

爬虫实战 | 爬取东方财富网经济数据——以居民消费价格指数(CPI)为例

Seminar|媒体关联董事对融资和外部治理的影响神奇的组内交叉合并 PDF分章节转TXT并实现可视化——以胡景北知青日记1971至1978年为例

万物皆可开——shellout妙用

无处不在的系列配置项|从零开始的Pyecharts(三)

使用Python制作自动聊天机器人  

fillin一下,平衡回来~

order命令——快速改变变量顺序的利器 Ajax应用场景——以获取雪球网港股代码及公司名称为例

播放列表中的歌单排行 

在Stata中轻松运用program编写命令

Meta Analysis in Stata17      

芒果TV视频弹幕爬取之《我在他乡挺好的》

Stata中的判断神器——confirm命令

cngdf——名义GDP与实际GDP之间的摆渡船

最近《扫黑风暴》有点火爆!我从豆瓣评论中发现了这些……

随机森林-Random Forest 

复原之神--preserve&restore

合并,“纵”享新丝滑:frameappend & xframeappend
什么是全局配置项?|从零开始的Pyecharts(二)帮你拿下数据可视化|从零开始的Pyecharts 

Stata助力疫情打卡管理——是谁没有接龙呢?


关于我们 


   微信公众号“Stata and Python数据分析”分享实用的Stata、Python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。

   武汉字符串数据科技有限公司一直为广大用户提供数据采集和分析的服务工作,如果您有这方面的需求,请发邮件到statatraining@163.com,或者直接联系我们的数据中台总工程司海涛先生,电话:18203668525,wechat: super4ht。海涛先生曾长期在香港大学从事研究工作,现为知名985大学的博士生,爬虫俱乐部网络爬虫技术和正则表达式的课程负责人。



此外,欢迎大家踊跃投稿,介绍一些关于Stata和Python的数据处理和分析技巧。

投稿邮箱:statatraining@163.com投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里
为作者署名,并有赏金分成。

2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众
号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存