资讯专栏INFORMATION COLUMN

从13万猫眼评论看看《流浪地球》到底怎么样

lemanli / 3148人阅读

摘要:今年的流浪地球这么火,通过爬取猫眼电影上网友对该片的评价如何。也许很多人在这天通过看流浪地球过节吧。

背景

最近几年猫眼电影越来越热门了,都差不多和豆瓣并驾齐驱了。今年的《流浪地球》这么火,通过爬取猫眼电影上网友对该片的评价如何。

爬取猫眼评论 找到评论网页地址

先打开猫眼官网找到《流浪地球》的介绍页面:https://maoyan.com/films/248906

虽然显示有112.4万人评分,但是页面只有热门短评,其他评论都去哪里了,手机明明是有的。

那么我们用chrome切换到手机页面:

打开开发者工具

开启手机浏览功能

访问手机版地址:http://m.maoyan.com/movie/248...$from=canary#

这时候我们就看到了所有的评论。

获取评论请求地址

在点击打开“查看全部330613条讨论”后,发现评论分为最热和最新两部分,最热数量有限,而最新则是未经过处理的,也正是我们需要的。通过search来查看下对应的请求:

发现,在chrome 的网络展示中发现只有一个类型为document的请求包含了所需的信息。那么这部分的评论获取就需要解析网页了,我们再把屏幕上的评论往下拉,发现会自动加载更多的评论,对应的chrome网络请求多出来了两个comments.json的请求:

果然这才是我们需要的!把初始页面的url和这两个json请求的url复制到一起比较一下:

http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=0&limit=15&ts=0&type=3
http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=15&limit=15&ts=1549965527295&type=3
http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=30&limit=15&ts=1549965527295&type=3

我们可以发现规律:

初始页面的ts值为0,随后会有ts值,且保持不变。这里的ts是当前的时间戳,可以通过转换工具查看:

offset是请求评论开始的序号,limit为请求的条数

再看返回的json结果:

data.comments中是评论的具体内容

paging中通过hasMore来告诉我们是否还有更多(判断是否继续抓取)

我们再尝试下将offset设置为0,也加上ts参数:

http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=0&limit=15&ts=1549965527295&type=3

发现也是可以获取数据的:

那么通过offsetlimit来控制每次请求获取的数量。

我们还可以通过加大limit参数来尝试,是否可以一次性获取更多的评论:

http://m.maoyan.com/review/v2/comments.json?movieId=248906&userId=-1&offset=0&limit=30&ts=1549965527295&type=3

效果如下:

再增加limit的值,会发现评论数回到了15条,可见猫眼系统仅支持每次最多获取30条。

构造请求url 方法一

根据上面的分析,我们构造请求的url就很明确了:

offset=0&limit=30开始

通过返回的paging.hasMore来判断是否继续抓取

下一个抓取的urloffset+=limit

只能抓取1000条?!

根据上述分析,在返回的json数据中是可以看到总评论数的,但是实际抓取的时候,在offset超过1000之后,返回的数据中hasMore就变成了false

于是尝试通过浏览器一直下拉刷新,到达offset超过1000的情况,发现页面会不停的发送请求,但也无法获取数据。

那应该就是网站做了控制,不允许offset超过1000。

构造请求URL 方法二

那么就要考虑其他构造url的方法来抓取了。先观察下每个请求返回的信息:

发现每个comment里都包含有一个time信息,把time做一下处理:

2019-02-13 13:38:00##感觉韩朵朵这个人设是多余的
2019-02-13 13:38:00##真的感动 非常棒
2019-02-13 13:38:00##这电影大陆的起航
2019-02-13 13:38:00##不怎么样,剧情挺感人,但是有点尴尬
2019-02-13 13:37:00##好看。。。。。。。。。。
2019-02-13 13:37:00##超级超级超级超级超级超级超级好看
2019-02-13 13:37:00##太牛逼了,中国科幻片可有一部能看的了。支持吴京
2019-02-13 13:36:00##不错!中国科幻的希望
2019-02-13 13:36:00##中国里程碑式的科幻电影。
2019-02-13 13:36:00##什么垃圾座位没人管的么乱坐的

可以发现后台是按照时间顺序的,每分钟一个间隔,那么就可以考虑根据每次返回comment中的时间来更新url中的ts即可。

由于不确定每次请求返回的数据中包含了多长的时间段,且返回的第一个评论时间戳与第二个评论是不同的,所以抓取思路如下:

获取请求数据

记录第一个时间戳

记录第二个时间戳

当遇到第三个时间戳时,将ts设置为第二个时间戳,重新构造url

如果单次抓取中每遇到第三个时间戳,则通过修改offset来继续抓取,直到遇到第三个时间戳

抓取实现

根据上面思路,实现相对就比较简单了:

生成url

def get_url():
    global offset
    url = "http://m.maoyan.com/review/v2/comments.json?movieId=" + movieId + "&userId=-1&offset=" + str(
        offset) + "&limit=" + str(limit) + "&ts=" + str(ts) + "&type=3"
    return url

访问url

def open_url(url):
    global ua
    try:
        headers = {"User-Agent": ua.random}
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.text
        else:
            return None
    except Exception as e:
        print(e)
        return None

数据处理:将评论保存并判断是否要继续抓取

def parse_json(data):
    global count
    global offset
    global limit
    global ts
    ts_duration = ts
    res = json.loads(data)
    comments = res["data"]["comments"]
    for comment in comments:
        comment_time = comment["time"]
        if ts == 0:
            ts = comment_time
            ts_duration = comment_time
        if comment_time != ts and ts == ts_duration:
            ts_duration = comment_time
        if comment_time !=ts_duration:
            ts = ts_duration
            offset = 0
            return get_url()
        else:
            content = comment["content"].strip().replace("
", "。")
            print("get comment " + str(count))
            count += 1
            write_txt(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(comment_time/1000)) + "##" + content + "
")
    if res["paging"]["hasMore"]:
        offset += limit
        return get_url()
    else:
        return None

最后一共抓取评论131106条,足够做各种分析了

2019-02-13 18:13:11,625 - get_comments.py[line:78] - INFO: get comment 131104
2019-02-13 18:13:11,729 - get_comments.py[line:78] - INFO: get comment 131105
2019-02-13 18:13:11,827 - get_comments.py[line:78] - INFO: get comment 131106
2019-02-13 18:13:15,416 - get_comments.py[line:98] - INFO: end
数据分析 按日期汇总分析热度

前面我们再抓取时,将评论的时间和内容通过csv的格式保存下来,并使用;分割。读取csv文件并统计处理就要用到大名鼎鼎的pandas了。

读取数据

pandas提供read_csv方法来直接独处数据保存为DateFrame格式。

df = pd.read_csv("comment.csv", sep=";", header=None)

设置数据列名

由于我们知道数据有两列,先通过这只列名可以方便后续引用。

df.columns = ["date", "comment"]

时间日期处理

date列,我们保存的数据格式是string,需要把转换为日期格式才能进一步处理。

df["date"] = pd.to_datetime(df["date"])

我们需要按时间来统计,所以把date列设置为index:

df = df.set_index("date")

日期筛选

由于我们知道《流浪地球》是2月5日上映的,我们可以对日期进行限定,以免出现有些在上映前的评论,会占用大段的空白情况。

设置index之后,可以参考list类型操作,由于时间是倒序的,所以可以直接使用[:"2019-02-04"]来选取2月4日之后到今天的所有数据。pandas在数据筛选方面相当智能,按照datetime的格式直接筛选即可。

cacu_df = df[:"2019-02-04"]

按日期进行数量统计

pandas中,通过resample方法进行重新采样,通过传入rule参数就可以按需要的频率获取数据,获得一个resampler对象。

DataFrame.resample(rule, how=None, axis=0, fill_method=None, closed=None, label=None, convention="start", kind=None, loffset=None, limit=None, base=0, on=None, level=None)

resampler对象提供了很多的统计方法,比如汇总求和可使用Resampler.count()

# 按日统计数量
cacu = cacu_df.resample("D").count()

这样就完成了按日期求和统计操作。

绘图

画图需要使用matplotlib库,通过导入该库,可直接对DateFrame对象进行画图处理。画图及图表格式化如下:

# 设置中文字体
font = FontProperties(fname="/System/Library/Fonts/PingFang.ttc")
plt.plot(cacu)
plt.title("流浪地球评论分析", fontproperties=font)
plt.xlabel("日期", fontproperties=font)
plt.ylabel("评论数", fontproperties=font)
plt.axis("tight")
# 显示网格
plt.grid(True)
# 自动旋转横轴日期
plt.gcf().autofmt_xdate()
# 显示数值
for a, b in zip(cacu.index, cacu.values):
plt.text(a, b, str(b[0]))
# 保存图片
plt.savefig("comment_analysis.png")
# 查看图片
plt.show()

分析结果

结果如下:

可见从上映之后,关注度直线飙升,到2月10日之后(上映5天),大家关注度逐渐下降。其中2月14日为情人节,大家的关注又有了小幅的上升。也许很多人在这天通过看《流浪地球》过节吧。

制作评论热点图云

数据清洗

首先由于评论是用户发表的,可能什么字符都会有,要先把一些特殊符号去掉,这里就用到了正则替换:

msg = re.sub("[s+.!/_,$%^*()+""?]+|[+——!,。?、~@#¥%……&*()【】;:]+|[.+]|[.+]", "", line)

分词与标签

清洗后的数据,可以使用jieba分词包来进行分词,并把所有的分词保存在一个list中,然后计算出每个分词出现的次数。

# 分词
tags = jieba.analyse.extract_tags(msg)
for t in tags:
    word_list.append(t)
# 计算词频
for word in word_list:
    if word not in word_dict:
        word_dict[word] = 1
    else:
        word_dict[word] += 1

生成词云

使用wordcloud包,就可以很方便的生成词云图片了。

先新建一个WordCloud对象,进行配置,然后利用前面的分词词频就可以生成对应的图片了。

# 计算图片颜色
alice_coloring = np.array(img)
my_wordcloud = WordCloud(background_color="white",
                             max_words=500, mask=alice_coloring,
                             max_font_size=200, random_state=42,
                             font_path=(os.path.join(d, "font/msyh.ttf")))
                             
my_wordcloud = my_wordcloud.generate_from_frequencies(wordList)

这里需要注意的是:

mask=alice_coloring:这里通过numpy将图片矩阵化,来获取图片的颜色作为WordCloudmask,是为了最后生成的图云不仅外形与我们输入的图片保持一致,而且整体颜色也保持一致。

输入的原图,背景色需要设置为白色而不是透明色,否则会全屏幕都是字。。。

对于中文的词云,需要制定中文的字体,这里用的是微软雅黑

保存图片

最后使用matplotlib.pyplot来保存图片,保存前要进行图片属性的一些设置。

width = img.width/80
height = img.height/80
plt.figure(figsize=(width, height))
plt.imshow(my_wordcloud.recolor(color_func=image_colors))
plt.imshow(my_wordcloud)
plt.axis("off")
# 通过设置subplots_adjust来控制画面外边框
plt.subplots_adjust(bottom=.01, top=.99, left=.01, right=.99)
plt.savefig("jupiter_wordcloud_1.png")
plt.show()

这里需要注意的是: 建议根据原图片的长宽比例进行一定的缩小,以免生成的图片像素过大而产生报错。

ValueError: Image size of 98400x46500 pixels is too large. It must be less than 2^16 in each direction.

词云展示

放一张原图,你能看的出来嘛,抠图技术有限O(∩_∩)O哈哈~

以上就是使用抓取的评论生成词云的大致思路,完成的实现代码请见:https://github.com/keejo125/w...

如果有更好的方法,欢迎一起探讨。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/43242.html

相关文章

  • 2018电影票房分析-谁才是票房之王

    摘要:另外由于豆瓣上一些电影评分数量太少而不显示,所以这里的电影数量会和票房数量有所差异。月度票房将类型片的票房按月划分,得到了这张图。 去年末的时候,我招收了新的 实训生 。本文是其中一位 @齐大圣 同学在实训两个月时完成的项目案例。(码上行动群里同学应该都看过这个名字,现在也是助教之一。)项目最初的想法是, 从互联网上的公开信息中采集2018年在国内上映电影的票房、评分、类型、演员等信息...

    stormjun 评论0 收藏0
  • 实战!《长津湖》为什么这么火爆?我用 Python 来分析猫眼影评

    摘要:作者周萝卜链接长津湖猫眼影评欢迎关注,专注数据分析数据挖掘好玩工具对于这个十一黄金周的电影市场,绝对是长津湖的天下,短短几天,票房就已经突破亿,大有奋起直追战狼的尽头。 ...

    lijy91 评论0 收藏0
  • 用python模拟《流浪地球》的木星引力弹弓效应

    摘要:来源重力助推而在影片中,也就是为了获取更大的速度以脱离太阳系,人类才选择借助木星的引力弹弓效应。引力弹弓的概念在几年前的星际穿越和火星救援中都有提及,我一直想写个模拟,直到这次趁流浪地球热映的机会才动手实现。 本文涉及影片内容,但算不上剧透。想看还未看的同学请谨慎阅读。 春节档的几部电影里,《 流浪地球 》成为一匹黑马,刷爆微博和朋友圈,从最初不高的排片率,一跃上升到票房榜首。 看过影...

    fsmStudy 评论0 收藏0
  • [数读]开户数看这一波牛市

    摘要:最近的股市有点热闹上证指数从开年的点,几乎一路涨到前几天的点,短短两个月,最高涨幅超过。横轴是日期,纵轴红线是上证指数,绿线和蓝柱是什么数据大家可以先自己猜一下。 注:本文首发于2019年3月11日。本想等3月的官方报告出来后修正文中数据。但很神奇的是,本文发布之后,中登公司的每周数据就再无更新。直到近日,公布了3月的月度数据,确实在意料之中,环比增加了一倍。 最近的股市有点热闹:上证...

    txgcwm 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<