小本聪作者玖蓁微信编辑周岩责任编辑

Python爬取《流浪地球》豆瓣影评与数据分析

编者按

猪年春节的贺岁档电影火爆异常,尤其是口碑爆棚的《流浪地球》更是收获的无数影迷和国人的赞誉。事实胜于雄辩,数据是最有力度的事实。我们用python爬取了豆瓣的影评,客观的分析一下这部国产的划时代的科幻电影。事实证明,《流浪地球》是非常值得观看的电影,并且这部电影正在带领中国的科幻产业走向成熟。

大年初一《流浪地球》全国上映。在豆瓣评分上,首日开分站稳8分以上,延续了之前点映的高口碑。微博上跟着出现吴京客串31天与投资6000万的热搜。知乎上关于“如何评价刘慈欣小说改编的同名电影《流浪地球》”的回答引起了众多人关注,包括该片导演郭帆的最高赞回答。

本篇文章爬取了豆瓣网上《流浪地球》的部分影评,并进行数据分析及可视化处理。下面是爬取分析的整个过程,让我们愉快开始吧!

一、网页分析

豆瓣网从2017年10月开始全面禁止爬取数据。在非登录状态下仅仅可以爬取200条短评,登录状态下仅可以爬取500条数据。白天一分钟最多可爬40次,晚上60次,超过次数就会封IP地址。小本聪爬取数据获得400条时被封了IP,账号被强制下线封号,之后发短信账号恢复,因此不建议多次爬取(另外,有很多解决方法,请自行搜索)。

获取对象
  • 评论用户

  • 评论内容

  • 评分

  • 评论日期

  • 用户所在城市

值得注意的是,在地址栏我们会发现电影名字的ID编号为26266893(其他电影只需更换ID即可),并且每页有20条短评,因此我爬取了20页。评论页面没有用户所在城市,需要进入用户页面获取信息。

二、数据获取与存储

1 获取cookies

小本聪用的是Chrome浏览器,Ctrl+F12进入开发者工具页面。F5刷新一下出现数据,找到cookies、headers。

2 加载headers、cookies,并用requests库获取信息
def get_content(id, page):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}
    cookies = {'cookie': 'bid=GOOb4vXwNcc; douban-fav-remind=1; ps=y; ue="maplekonghou@163.com"; push_noty_num=0; push_doumail_num=0; ap=1; ll="108288"; dbcl2="181095881:BSb6IVAXxCI"; ck=Fd1S; ct=y'}
    url = "https://movie.douban.com/subject/" + str(id) + "/comments?start=" + str(page * 10) + "&limit=20&sort=new_score&status=P"
    res = requests.get(url, headers=headers, cookies=cookies)
3 解析需求数据

此处运用xpath解析。发现有的用户虽然给了评论,但是没有给评分,所以score和date这两个的xpath位置是会变动的。因此需要加判断,如果发现score里面解析的是日期,证明该条评论没有给出评分。

for i in range(1, 21):   # 每页20个评论用户
    name = x.xpath('//*[@id="comments"]/div[{}]/div[2]/h3/span[2]/a/text()'.format(i))
    # 下面是个大bug,如果有的人没有评分,但是评论了,那么score解析出来是日期,而日期所在位置spen[3]为空
    score = x.xpath('//*[@id="comments"]/div[{}]/div[2]/h3/span[2]/span[2]/@title'.format(i))
    date = x.xpath('//*[@id="comments"]/div[{}]/div[2]/h3/span[2]/span[3]/@title'.format(i))
    m = '\d{4}-\d{2}-\d{2}'
    try:
        match = re.compile(m).match(score[0])
    except IndexError:
        break
    if match is not None:
        date = score
        score = ["null"]
    else:
        pass
    content = x.xpath('//*[@id="comments"]/div[{}]/div[2]/p/span/text()'.format(i))
    id = x.xpath('//*[@id="comments"]/div[{}]/div[2]/h3/span[2]/a/@href'.format(i))
    try:
        city = get_city(id[0], i)  # 调用评论用户的ID城市信息获取
    except IndexError:
        city = " "
    name_list.append(str(name[0]))
    score_list.append(str(score[0]).strip('[]\''))  # bug 有些人评论了文字,但是没有给出评分
    date_list.append(str(date[0]).strip('[\'').split(' ')[0])
    content_list.append(str(content[0]).strip())
    city_list.append(city)
4 获取电影名称

从url上只能获取电影的subject的8位ID数值,引起需要自行解析网页获取ID号对应的电影名称,该功能是后期改进添加的,因此为避免现有代码改动多(偷个懒),采用了全局变量赋值给movie_name,需要注意全局变量调用时,要加global声明一下。

pattern = re.compile('<div id="wrapper">.*?<div id="content">.*?<h1>(.*?) 短评</h1>', re.S)
global movie_name
movie_name = re.findall(pattern, res.text)[0]  # list类型
5 数据存储

由于数据不多,选择CSV存储即可。

def main(ID, pages):
    global movie_name
    for i in tqdm(range(0, pages)):  # 豆瓣只开放500条评论
        get_content(ID, i)  # 第一个参数是豆瓣电影对应的id序号,第二个参数是想爬取的评论页数
        time.sleep(round(random.uniform(3, 5), 2))  # 设置延时发出请求
    infos = {'name': name_list, 'city': city_list, 'content': content_list, 'score': score_list, 'date': date_list}
    data = pd.DataFrame(infos, columns=['name', 'city', 'content', 'score', 'date'])
    data.to_csv(movie_name + ".csv")  # 存储名为 电影名.csv

三、数据分析与可视化

1 获取cookies

城市信息筛选中文字

def translate(str):
    line = str.strip()
    p2 = re.compile('[^\u4e00-\u9fa5]')   # 中文的编码范围是:\u4e00到\u9fa5
    zh = " ".join(p2.split(line)).strip()
    zh = ",".join(zh.split())
    str = re.sub("[A-Za-z0-9!!,%\[\],。]", "", zh)
    return str

匹配pyecharts支持的城市列表

 d = pd.read_csv(csv_file, engine='python', encoding='utf-8')
 motion_list = []
 for i in d['content']:
   try:
       s = round(SnowNLP(i).sentiments, 2)
       motion_list.append(s)
   except TypeError:
       continue
   result = {}
   for i in set(motion_list):
       result[i] = motion_list.count(i)
   return result
2 基于snownlp的情感分析

snownlp主要可以进行中文分词(算法是Character-Based Generative Model)、词性标注(原理是TnT、3-gram 隐马)、情感分析(官网木有介绍原理,但是指明购物类的评论的准确率较高,其实是因为它的语料库主要是购物方面的,可以自己构建相关领域语料库,替换原来的,准确率也挺不错的)、文本分类(原理是朴素贝叶斯)、转换拼音、繁体转简体、提取文本关键词(原理是TextRank)、提取摘要(原理是TextRank)、分割句子、文本相似(原理是BM25)【摘自CSDN】。在看此之前,建议先看一下官网,里面有最基础的一些命令的介绍。官网链接:https://pypi.org/project/snownlp/

由于snownlp全部是unicode编码,所以要注意数据是否为unicode编码。因为是unicode编码,所以不需要去除中文文本里面含有的英文,因为都会被转码成统一的编码上面只是调用snownlp原生语料库对文本进行分析,snownlp重点针对购物评价领域,所以为了提高情感分析的准确度可以采取训练语料库的方法。

attr, val = [], []
info = count_sentiment(csv_file)
info = sorted(info.items(), key=lambda x: x[0], reverse=False)  # dict的排序方法
for each in info[:-1]:
    attr.append(each[0])
    val.append(each[1])
line = Line(csv_file+":影评情感分析")
line.add("", attr, val, is_smooth=True, is_more_utils=True)
line.render(csv_file+"_情感分析曲线图.html")

3 评论来源城市分析

调用pyecharts的page函数,可以在一个图像对象中创建多个chart,只需要对应的add即可。

    geo1 = Geo("", "评论城市分布", title_pos="center", width=1200, height=600,
              background_color='#404a59', title_color="#fff")
    geo1.add("", attr, val, visual_range=[0, 300], visual_text_color="#fff", is_geo_effect_show=False,
            is_piecewise=True, visual_split_number=10, symbol_size=15, is_visualmap=True, is_more_utils=True)
    # geo1.render(csv_file + "_城市dotmap.html")
    page.add_chart(geo1)
    geo2 = Geo("", "评论来源热力图",title_pos="center", width=1200,height=600, background_color='#404a59', title_color="#fff",)
    geo2.add("", attr, val, type="heatmap", is_visualmap=True, visual_range=[0, 50],visual_text_color='#fff', is_more_utils=True)
    # geo2.render(csv_file+"_城市heatmap.html")  # 取CSV文件名的前8位数
    page.add_chart(geo2)
    bar = Bar("", "评论来源排行", title_pos="center", width=1200, height=600 )
    bar.add("", attr, val, is_visualmap=True, visual_range=[0, 100], visual_text_color='#fff',mark_point=["average"],mark_line=["average"],
            is_more_utils=True, is_label_show=True, is_datazoom_show=True, xaxis_rotate=45)
    bar.render(csv_file+"_城市评论bar.html")  # 取CSV文件名的前8位数
    page.add_chart(bar)
    pie = Pie("", "评论来源饼图", title_pos="right", width=1200, height=600)
    pie.add("", attr, val, radius=[20, 50], label_text_color=None, is_label_show=True, legend_orient='vertical', is_more_utils=True, legend_pos='left')
    pie.render(csv_file + "_城市评论Pie.html")  # 取CSV文件名的前8位数
    page.add_chart(pie)
    page.render(csv_file + "_城市评论分析汇总.html")

4 影片情感分析

0.5以下为负面情绪,0.5以上为正面情绪。可以看到好评还是很不错的,至于豆瓣上一些看衰评论只是少数。

5 电影评分走势分析
  • 读取csv文件,以dataframe(df)形式保存

  • 遍历df行,保存到list

  • 统计相同日期相同评分的个数

  • 转换为df格式,设置列名

  • 按日期排序

  • 遍历新的df,每个日期的评分分为5种,因此需要插入补充缺失数值。

creat_df = pd.DataFrame(columns = ['score', 'date', 'votes']) # 创建空的dataframe
for i in list(info_new['date']):
    location = info_new[(info_new.date==i)&(info_new.score=="力荐")].index.tolist()
    if location == []:
        creat_df.loc[mark] = ["力荐", i, 0]
        mark += 1
    location = info_new[(info_new.date==i)&(info_new.score=="推荐")].index.tolist()
    if location == []:
        creat_df.loc[mark] = ["推荐", i, 0]
        mark += 1
    location = info_new[(info_new.date==i)&(info_new.score=="还行")].index.tolist()
    if location == []:
        creat_df.loc[mark] = ["还行", i, 0]
        mark += 1
    location = info_new[(info_new.date==i)&(info_new.score=="较差")].index.tolist()
    if location == []:
        creat_df.loc[mark] = ["较差", i, 0]
        mark += 1
    location = info_new[(info_new.date==i)&(info_new.score=="很差")].index.tolist()
    if location == []:
        creat_df.loc[mark] = ["很差", i, 0]
        mark += 1
info_new = info_new.append(creat_df.drop_duplicates(), ignore_index=True)

由于允许爬取的量少和时间问题,部分数据不是很明显。但依然可以得出一些发现。在影片上映开始的一周内,为评论高峰,尤其是上映3天内,这符合常识,但是也可能有偏差,因为爬虫获取的数据是经过豆瓣电影排序的,倘若数据量足够大得出的趋势可能更接近真实情况。

另外发现,影片在上映前也有部分评论,分析可能是影院公映前的小规模试映,且这些提前批的用户的评分均值,差不多接近影评上映后的大规模评论的最终评分 ,从这些细节中,我们或许可以猜测,这些能提前观看影片的,可能是资深影迷或者影视从业人员,他们的评论有着十分不错的参考价值。

6 影评词云图

词云图制作时,先读取CSV文件一dataframe形式保存,去除评论中非中文文本,选了胡歌照片作为背景,并设置了停用词表。

wc = WordCloud(width=1024, height=768, background_color='white',
     mask=backgroud_Image, font_path="C:\simhei.ttf",
     stopwords=stopwords, max_font_size=400,random_state=50)

可以看到高频词“可以”表现出对该片的认可,“特效”体现出特效镜头对科幻片的重要性,“科幻电影”体现出影迷对科幻类电影的浓厚兴趣。

以上就是本次爬取豆瓣网《流浪地球》短评的过程与数据分析

运筹OR帷幄
运筹OR帷幄

『运筹OR帷幄』是大数据人工智能时代的运筹学,普及运筹学和优化理论,及其在人工智能和供应链中的应用。

工程情感分析词性标注文本分类数据分析流浪星球Python
3
相关数据
数据分析技术

数据分析是一类统计方法,其主要特点是多维性和描述性。有些几何方法有助于揭示不同的数据之间存在的关系,并绘制出统计信息图,以更简洁的解释这些数据中包含的主要信息。其他一些用于收集数据,以便弄清哪些是同质的,从而更好地了解数据。 数据分析可以处理大量数据,并确定这些数据最有用的部分。

参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

文本分类技术

该技术可被用于理解、组织和分类结构化或非结构化文本文档。文本挖掘所使用的模型有词袋(BOW)模型、语言模型(ngram)和主题模型。隐马尔可夫模型通常用于词性标注(POS)。其涵盖的主要任务有句法分析、情绪分析和垃圾信息检测。

词性标注技术

词性标注是指为分词结果中的每个单词标注一个正确的词性的程序,也即确定每个词是名词、动词、形容词或其他词性的过程。

准确率技术

分类模型的正确预测所占的比例。在多类别分类中,准确率的定义为:正确的预测数/样本总数。 在二元分类中,准确率的定义为:(真正例数+真负例数)/样本总数

朴素贝叶斯技术

朴素贝叶斯是一种构建分类器的简单方法。该分类器模型会给问题实例分配用特征值表示的类标签,类标签取自有限集合。它不是训练这种分类器的单一算法,而是一系列基于相同原理的算法:所有朴素贝叶斯分类器都假定样本每个特征与其他特征都不相关。举个例子,如果一种水果其具有红,圆,直径大概3英寸等特征,该水果可以被判定为是苹果。尽管这些特征相互依赖或者有些特征由其他特征决定,然而朴素贝叶斯分类器认为这些属性在判定该水果是否为苹果的概率分布上独立的。

语料库技术

语料库一词在语言学上意指大量的文本,通常经过整理,具有既定格式与标记;事实上,语料库英文 "text corpus" 的涵意即为"body of text"。

知乎机构

知乎作为中文互联网知名知识内容平台,致力于构建一个人人都可接入的知识分享网络,让人们便捷地与世界分享知识、经验和见解,高效获得可信赖的解答。 目前,知乎已经覆盖「问答」社区、一站式知识服务平台「知乎大学」、短内容分享功能「想法」等一系列产品和服务,并建立了包括音频、视频在内的多元媒介形式。截止 2018 年 8 月底,知乎用户数已突破 2 亿,回答数超过 1.2 亿。未来,知乎进一步加大对 AI 技术和应用的投入,构建一个由 AI 驱动的智能社区,让知识普惠每一个人。

https://www.zhihu.com
推荐文章
暂无评论
暂无评论~