猫眼电影诛仙评论爬取并进行数据分析

近期【诛仙】电影评论如潮,有褒有贬。我们现在针对此电影进行用户评论信息的爬取,并进行数据的分析。
在这里插入图片描述
在这里插入图片描述

由于猫眼电影评论数据是动态加载的,所以我们我们不可能通过requests直接请求电影页面进行获取,现在必须找到相应的接口,从接口中拿到数据信息。

猫眼电影评论接口的查找和之前的网站有一些区别。可以发现该网页的评论数量只显示到了十条评论数据。
在这里插入图片描述
如果想要查找到接口,需要将其装换为app_web的方式:
具体操作步骤:
**1、打开开发者工具,点击左上角的手机按钮,让请求变为手机web请求
**
在这里插入图片描述
在这里插入图片描述
2、使用F5进行刷新当前页面,使其变为手机App页面类型
当刷新完毕后,可以发现当前页面url也会发生变化
在这里插入图片描述
注意这里的user-agent其实也发生了变化,为Android 版本方式。我们请求是填写的请求头需要填这一个,而不是之前电脑版谷歌的
在这里插入图片描述
3、寻找评论接口
我们需要点击查看更多评论,一直往下刷新评论接口才会显示出来
在这里插入图片描述
在这里插入图片描述
http://m.maoyan.com/review/v2/comments.json?movieId=360504&userId=-1&offset=0&limit=15&ts=0&type=3
在这里插入图片描述
json数据主要参数说明:
在这里插入图片描述
这个就是我们找到的猫眼电影评论的接口,只不过此接口经过测试。只能爬取到前1000条评论数量。
该接口url参数说明:

  • movieId 电影id
  • userId=-1 用户id,就默认-1
  • offset 偏移量,指每次获取评论时的起始索引,向后取15条 只能取到前1000条评论,后面可能反爬措施
  • limit 限制返回的数据量 经测试最多返回21条数据
  • ts 处理后的时间戳
  • type=3 类型,默认为3

我们主要更改offset和ts参数就可以进行评论数据的返回。

将1000条评论数据先爬取下来,保存至csv文件中,以便后面的数据分析

import csv
import json
import time
import requests
# 保存数据为csv数据
def save_data_csv(data):
    with open('zhuxian2.csv','a',encoding='utf-8-sig',newline='')as fp:
        # 创建写对象
        writer = csv.writer(fp)
        title = ['nick','gender','score','content','upCount','userLevel']
        # 解决循环存储,表头重复问题
        with open('zhuxian2.csv','r',encoding='utf-8-sig',newline='')as fp:
            # 创建读对象
            reader = csv.reader(fp)
            if not [row for row in reader]:
                writer.writerow(title)
                writer.writerow([data[i] for i in title])
            else:
                writer.writerow([data[i] for i in title])

    print('*'*10+'保存完毕'+'*'*10)
# 请求目标页面,提取数据
def get_film_data(offset = 0):
    # url = 'https://maoyan.com/films/360504'
    # 该接口链接中的参数:
    #   movieId 影片id
    #   userId  用户id    -1默认
    #   offset  偏移量 指每次获取评论时的起始索引,向后取15条 只能取到前1000条评论,后面可能反爬措施
    #   limit   限制返回的数据量 经测试最多返回21条数据
    #   ts      第一次访问为0,之后再前一次请求返回的数据中,时间戳
    #   type    类型 默认3
    localtime = time.time()
    # 构建一个格式化后的时间戳
    ts = int(localtime * 1000)
    # 但是要注意对时间进行转换,空格对应的是%20,冒号对应的是%3A
    url = f'http://m.maoyan.com/review/v2/comments.json?movieId=360504&userId=-1&offset={offset}&limit=15&ts={ts}&type=3'
    headers = {
        'Host': 'm.maoyan.com',
        'Referer': 'http://m.maoyan.com/movie/360504/comments?_v_=yes',
        'User-Agent': 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Mobile Safari/537.36'
    }

    cookies = {
        'Cookie: __mta': '245856187.1566377737537.1569416094603.1569416143850.11',
    '__mta': '245856187.1566377737537.1569416143850.1569486806493.12',
    'uuid_n_v': 'v1',
    'iuuid': '942C12B0DF4311E9ADA9C1C3B540BA45F066B2B3028841B8A0BC3544E4C0AD17',
    'ci': '1%2C%E5%8C%97%E4%BA%AC',
    '_lxsdk_cuid': '16d6c9b401ec8-0c6c86354bd8a9-5b123211-100200-16d6c9b401ec8',
    'webp': 'true',
    '_lxsdk': '942C12B0DF4311E9ADA9C1C3B540BA45F066B2B3028841B8A0BC3544E4C0AD17',
    '_lxsdk_s': '16d6c9aec69-db9-912-eec%7C%7C94' }
    # 开始页面请求,返回响应内容
    response = requests.get(url,headers=headers,cookies=cookies).json()
    # with open('zhuxian.html','w',encoding='utf-8')as fp:
    #     fp.write(response)
    # pprint(response)
    # 评论总数
    total = response['data']['total']

    # times = response['ts']

    comments = response['data']['comments']
    for comment in comments:
        data = {}
        # 用户昵称
        nick = comment['nick']
        # 用户性别 0女   1男  2未知
        gender = comment['gender']
        # 用户评分
        score = comment['score']
        # 用户评论内容
        content = comment['content']
        # 评论点赞数量
        upCount = comment['upCount']
        # 用户等级
        userLevel = comment['userLevel']
        print(nick,gender,score,content,upCount,userLevel)
        data['nick'] = nick
        data['gender'] = gender
        data['score'] = score
        data['content'] = content
        data['upCount'] = upCount
        data['userLevel'] = userLevel

        # save_data_csv(data)
    return total

if __name__ == '__main__':
    offset = 0
    while True:
        print(offset)
        total = get_film_data(offset)
        offset += 15
        if offset > total:
            break
        time.sleep(1)

在这里插入图片描述

根据爬取数据进行相关数据分析:
1、使用pandas读取文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2、自定义饼图函数

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 设置绘图风格
sns.set_style('ticks')
# plt.figure()
# # 解决matplotlib中文显示问题
plt.rcParams['font.sans-serif']='SimHei'
plt.rcParams['axes.unicode_minus']=False


# 饼图绘制函数
def pie(data=None,title=None,labels=None,length=6,height=6,dpi=100):
    # 创建画布和轴
    fig,ax = plt.subplots(figsize=(length,height),dpi=dpi)
    # plt.figure()
    size = 0.5
    # labels = data.index
    ax.pie(data,labels=labels,startangle=90,autopct='%.1f%%'
           ,colors=sns.color_palette('husl',len(data)),
           radius=1,# 饼图半径,默认为1
           pctdistance=0.75, # 控制百分比显示位置
           wedgeprops=dict(width=size,edgecolor='w'), # 控制甜甜圈的宽度
           textprops=dict(fontsize=10) # 控制字号及颜色
           )
    ax.set_title(title,fontsize=15)
    # plt.title(title)
    plt.show()

读取性别数据并进行计数排序
在这里插入图片描述
在这里插入图片描述
制作诛仙电影评论用户性别赞比饼图
在这里插入图片描述
在这里插入图片描述
可以看出本次用户评论人群性别的占比情况:女性居多,男性次之,其他未补全个人信息的用户占的比重也不少。

用户评分占比情况:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从此占比情况可以看出,猫眼电影用户对待诛仙的态度:37.2%的满分占比,其实就是1分和8分的,说明该该电影用户的认可度以及剧情方面还是没有收到广大消费者的认可。但用户整体情况还是可观的。

3、自定义柱状图函数

# 柱状图绘制函数
def bar(x,y,title=None):
    fig,ax = plt.subplots()
    # 参数x 类别数的标号
    # 参数y 各个类别所对应的类别的数量
    # 参数width 代表类别之间间距的百分比
    # 参数color 代表柱子的颜色,可以传带字符串,也可以传一个列表
    plt.bar(x, y, color='#DE48B5')
    # 柱状图标题
    plt.title(title)
    # 标注(每个点)
    # 增加网格曲线,只要y轴上的曲线,并设置透明度
    plt.grid(True, axis='y', alpha=1)
    for i, j in zip(x, y):
        # 参数1 标注的x轴位置
        # 参数2 标注的y轴位置
        # 参数3 标注的内容
        plt.text(i, j, '%d' % j, horizontalalignment='center', )
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    # ax.spines['left'].set_visible(False)

    # 显示图片
    plt.show()

读取用户等级数据,并制作为柱状图:
在这里插入图片描述
在这里插入图片描述
从柱状图中可以看出,该形状类似正态分布。0级和1级的用户比较少,应该属于新注册或注册不久的用户,用户评论水军的成分较少;大多数都是老用户。

4、读取评论内容数据,进行影评分词并制作词云

import jieba
from PIL import Image
import numpy as np
from wordcloud import WordCloud

# 3.影评分词
df['content'].to_csv('zhuxian_content.txt',index=False,encoding='utf-8')
with open('zhuxian_content.txt','r',encoding='utf-8')as fp:
    content = fp.read()
# 开始分词 使用jieba进行精确分词获取词语列表
words = jieba.lcut(content)
# 使用空格拼接获得字符串
words = ' '.join(words)
print(words)

# 生成词云
# 读取图片,生成图片形状
mask_pic = np.array(Image.open('1.jpg'))
words_cloud = WordCloud(
    background_color='white',# 词云图片的背景颜色
    width=800,height=600,# 词云图片的宽度,默认400像素;词云图片的高度,默认200像素
    font_path='msyh.ttf',# 词云指定字体文件的完整路径
    max_words=200,# 词云图中最大词数,默认200
    max_font_size=80,# 词云图中最大的字体字号,默认None,根据高度自动调节 min_font_size# 词云图中最小的字体字号,默认4号
    font_step=1, # 词云图中字号步进间隔,默认1
    random_state=30,# 设置有多少种随机生成状态,即有多少种配色方案
    mask=mask_pic# 词云形状,默认None,即方形图
).generate(words) # 有jieba分词拼接的字符串生成词云
words_cloud.to_file('诛仙评论词云.png') # 保存词云为图片


# 使用plt显示词云
#plt.imshow(words_cloud,interpolation='bilinear')
# 消除坐标轴
#plt.axis('off')
#plt.show()

在这里插入图片描述
可以看出评论关键字最多的还是:剧情,好看,电影,可以,不错等。

完整代码如下:

import io
import sys
import csv
import json
import time
import jieba
from PIL import Image
import numpy as np
from wordcloud import WordCloud
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import requests
from lxml import etree
from pprint import pprint


# 设置绘图风格
sns.set_style('ticks')
# plt.figure()
# # 解决matplotlib中文显示问题
plt.rcParams['font.sans-serif']='SimHei'
plt.rcParams['axes.unicode_minus']=False

# 改变标准输出的默认编码
# sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')

# 保存数据为csv数据
def save_data_csv(data):
    with open('zhuxian2.csv','a',encoding='utf-8-sig',newline='')as fp:
        # 创建写对象
        writer = csv.writer(fp)
        title = ['nick','gender','score','content','upCount','userLevel']
        # 解决循环存储,表头重复问题
        with open('zhuxian2.csv','r',encoding='utf-8-sig',newline='')as fp:
            # 创建读对象
            reader = csv.reader(fp)
            if not [row for row in reader]:
                writer.writerow(title)
                writer.writerow([data[i] for i in title])
            else:
                writer.writerow([data[i] for i in title])

    print('*'*10+'保存完毕'+'*'*10)
# 请求目标页面,提取数据
def get_film_data(offset = 0):
    # url = 'https://maoyan.com/films/360504'
    # 该接口链接中的参数:
    #   movieId 影片id
    #   userId  用户id    -1默认
    #   offset  偏移量 指每次获取评论时的起始索引,向后取15条 只能取到前1000条评论,后面可能反爬措施
    #   limit   限制返回的数据量 经测试最多返回21条数据
    #   ts      第一次访问为0,之后再前一次请求返回的数据中,时间戳
    #   type    类型 默认3
    localtime = time.time()
    # 构建一个格式化后的时间戳
    ts = int(localtime * 1000)
    # 但是要注意对时间进行转换,空格对应的是%20,冒号对应的是%3A
    url = f'http://m.maoyan.com/review/v2/comments.json?movieId=360504&userId=-1&offset={offset}&limit=15&ts={ts}&type=3'
    headers = {
        'Host': 'm.maoyan.com',
        'Referer': 'http://m.maoyan.com/movie/360504/comments?_v_=yes',
        'User-Agent': 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Mobile Safari/537.36'
    }

    cookies = {
        'Cookie: __mta': '245856187.1566377737537.1569416094603.1569416143850.11',
    '__mta': '245856187.1566377737537.1569416143850.1569486806493.12',
    'uuid_n_v': 'v1',
    'iuuid': '942C12B0DF4311E9ADA9C1C3B540BA45F066B2B3028841B8A0BC3544E4C0AD17',
    'ci': '1%2C%E5%8C%97%E4%BA%AC',
    '_lxsdk_cuid': '16d6c9b401ec8-0c6c86354bd8a9-5b123211-100200-16d6c9b401ec8',
    'webp': 'true',
    '_lxsdk': '942C12B0DF4311E9ADA9C1C3B540BA45F066B2B3028841B8A0BC3544E4C0AD17',
    '_lxsdk_s': '16d6c9aec69-db9-912-eec%7C%7C94' }
    # 开始页面请求,返回响应内容
    response = requests.get(url,headers=headers,cookies=cookies).json()
    # with open('zhuxian.html','w',encoding='utf-8')as fp:
    #     fp.write(response)
    # pprint(response)
    # 评论总数
    total = response['data']['total']

    # times = response['ts']

    comments = response['data']['comments']
    for comment in comments:
        data = {}
        # 用户昵称
        nick = comment['nick']
        # 用户性别 0女   1男  2未知
        gender = comment['gender']
        # 用户评分
        score = comment['score']
        # 用户评论内容
        content = comment['content']
        # 评论点赞数量
        upCount = comment['upCount']
        # 用户等级
        userLevel = comment['userLevel']
        print(nick,gender,score,content,upCount,userLevel)
        data['nick'] = nick
        data['gender'] = gender
        data['score'] = score
        data['content'] = content
        data['upCount'] = upCount
        data['userLevel'] = userLevel

        # save_data_csv(data)
    return total

# 饼图绘制函数
def pie(data=None,title=None,labels=None,length=6,height=6,dpi=100):
    # 创建画布和轴
    fig,ax = plt.subplots(figsize=(length,height),dpi=dpi)
    # plt.figure()
    size = 0.5
    # labels = data.index
    ax.pie(data,labels=labels,startangle=90,autopct='%.1f%%'
           ,colors=sns.color_palette('husl',len(data)),
           radius=1,# 饼图半径,默认为1
           pctdistance=0.75, # 控制百分比显示位置
           wedgeprops=dict(width=size,edgecolor='w'), # 控制甜甜圈的宽度
           textprops=dict(fontsize=10) # 控制字号及颜色
           )
    ax.set_title(title,fontsize=15)
    # plt.title(title)
    plt.show()

# 柱状图绘制函数
def bar(x,y,title=None):
    fig,ax = plt.subplots()
    # 参数x 类别数的标号
    # 参数y 各个类别所对应的类别的数量
    # 参数width 代表类别之间间距的百分比
    # 参数color 代表柱子的颜色,可以传带字符串,也可以传一个列表
    plt.bar(x, y, color='#DE48B5')
    # 柱状图标题
    plt.title(title)
    # 标注(每个点)
    # 增加网格曲线,只要y轴上的曲线,并设置透明度
    plt.grid(True, axis='y', alpha=1)
    for i, j in zip(x, y):
        # 参数1 标注的x轴位置
        # 参数2 标注的y轴位置
        # 参数3 标注的内容
        plt.text(i, j, '%d' % j, horizontalalignment='center', )
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    # ax.spines['left'].set_visible(False)

    # 显示图片
    plt.show()

if __name__ == '__main__':
    # offset = 0
    #
    # while True:
    #     print(offset)
    #     total = get_film_data(offset)
    #     offset += 15
    #     if offset > total:
    #         break
    #     time.sleep(1)

    # 数据分析
    df = pd.read_csv('zhuxian.csv',encoding='utf-8')
    print(df)
    #
    # # 1.观看人群性别
    # gender = df['gender'].value_counts().sort_index(ascending=1) # 1降序 女生居多
    # print(gender)
    # 饼图,标题:观看人群性别占比
    # 调用自定义饼图函数
    # pie(gender,title='【诛仙】观看人群性别占比',labels=['女','男','未知'])
    #
    # # 2.评分占比情况
    # score = df['score'].value_counts().sort_index(ascending=1)  # 1降序 女生居多
    # print(score)
    # 饼图,标题:观看人群性别占比
    # 调用自定义饼图函数
    # pie(score, title='【诛仙】评分占比', labels=score.index)
    #
    #
    # 3.影评分词
    # df['content'].to_csv('zhuxian_content.txt',index=False,encoding='utf-8')
    with open('zhuxian_content.txt','r',encoding='utf-8')as fp:
        content = fp.read()
    # 开始分词 使用jieba进行精确分词获取词语列表
    words = jieba.lcut(content)
    # 使用空格拼接获得字符串
    words = ' '.join(words)
    print(words)

    # 生成词云
    # 读取图片,生成图片形状
    mask_pic = np.array(Image.open('1.jpg'))
    words_cloud = WordCloud(
        background_color='white',# 词云图片的背景颜色
        width=800,height=600,# 词云图片的宽度,默认400像素;词云图片的高度,默认200像素
        font_path='msyh.ttf',# 词云指定字体文件的完整路径
        max_words=200,# 词云图中最大词数,默认200
        max_font_size=80,# 词云图中最大的字体字号,默认None,根据高度自动调节 min_font_size# 词云图中最小的字体字号,默认4号
        font_step=1, # 词云图中字号步进间隔,默认1
        random_state=30,# 设置有多少种随机生成状态,即有多少种配色方案
        mask=mask_pic# 词云形状,默认None,即方形图
    ).generate(words) # 有jieba分词拼接的字符串生成词云
    words_cloud.to_file('诛仙评论词云.png') # 保存词云为图片
    # 使用plt显示词云
    plt.imshow(words_cloud,interpolation='bilinear')
    # 消除坐标轴
    plt.axis('off')
    plt.show()

    # 4.用户等级柱状图分析
    # userLevel = df['userLevel'].value_counts().sort_index()
    # print(userLevel)
    #
    # x = userLevel.index
    # y = userLevel
    # bar(x,y,title='评论用户等级数量分布柱状图')


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孜孜孜孜不倦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值