赞
踩
每至暑期,电影市场都会掀起一波又一波的高潮,众多佳片在这个黄金档期相继上映,面临着激烈的票房争夺战。猫眼电影是美团旗下的一站式电影互联网平台,占据网络购票市场份额的40%以上,本文将基于selenium爬取猫眼实时票房网站,获取暑期综合票房、排片占比、排座占比等信息,并进行可视化分析。
一
网页分析
爬取的目标网页为猫眼电影实时票房常规版(https://piaofang.maoyan.com/box-office?ver=normal),选择该网页而不是专业版(https://piaofang.maoyan.com/dashboard)是因为专业版网页爬取难度较大。查看源码,可以看到在专业版网页中,综合票房显示为一段div包裹的不可见文本。对于常规版网页来说,票房数字在源码中正常显示,因此本文将爬取猫眼电影实时票房常规版网页的内容。
图1 猫眼电影实时票房专业版网页
图2 猫眼电影实时票房常规版网页
观察源码和网页内显示的内容是否一致。在源码中找到名为**的HTML标签,依次展开,发现网页呈现出的内容和源码一致。但在使用requests库请求该地址时发现得到的数据并不完整,这是因为该网页使用了异步加载方式。因此,接下来考虑使用selenium**库。
图3 观察源码
二
提取信息
首先引入库,使用webdriver进入页面。注意:在使用selunium之前要下载对应浏览器版本的webDriver驱动,解压后的存放路径为:浏览器的根目录下**(windows)、/usr/local/bin/(macos、linux)。本文使用的是chrome**浏览器:
from selenium import webdriver``from selenium.webdriver.common.by import By``driver = webdriver.Chrome()``driver.get('http://piaofang.maoyan.com/box-office?ver=normal')
然后观察网页结构,发现影片名称均存放在名称为p、属性class的值为“movie-name”的节点下,因此可以使用xpath元素进行定位,即**//\*[@class=‘movie-name’]**,并且具有唯一性。类似地,对于总票房、实时综合票房、综合票房占比、排片占比、排座占比均可使用xpath元素定位并获取元素。
图4 xpath元素定位
我们需要获取的是页面中的多个相同元素,因此使用find_elements,得到的是一个列表:
name = driver.find_elements(By.XPATH, "//*[@class='movie-name']")``sumBox = driver.find_elements(By.XPATH, "//*[@class='sumBox']")``box = driver.find_elements(By.XPATH, "//*[@class='boxDesc-wrap red-color']")``boxRate = driver.find_elements(By.XPATH, "//*[@class='boxRate-wrap']")``showRate = driver.find_elements(By.XPATH, "//*[@class='countRate-wrap']")``seatRate = driver.find_elements(By.XPATH, "//*[@class='seatRate-wrap']")
由于find_elements仅能获取元素,不能获取其中的数据。我们需要的数据是定位得到的标签对象的文本内容,因此使用element.text获取文本。本文封装了名为transfer_to_text的函数,依次从上述获得的所有元素中提取对应的文本内容。代码如下:
# 构造函数``def transfer_to_text(input_list):` `new_list = []` `for i in input_list:` `text_str = i.text` `new_list.append(text_str)` `return new_list` `# 提取文本内容``new_name = transfer_to_text(name)``new_sumBox = transfer_to_text(sumBox)``new_box = transfer_to_text(box)``new_boxRate = transfer_to_text(boxRate)``new_showRate = transfer_to_text(showRate)``new_seatRate = transfer_to_text(seatRate)
之后使用zip函数将以上获得的new_name、new_sumBox、new_box等列表组合成一个新的列表file_info,即为我们得到的电影票房数据(本文票房数据截止到7月28日)。
file_info= list(zip(new_name,new_sumBox,new_box,new_boxRate,new_showRate,new_seatRate))``print(file_info)
图5 获取的电影票房数据
还可以选择将数据写入excel文件,首先需要将元组列表转换为字典列表,然后创建dataframe并将数据写入,具体代码如下:
#输出为表格``import pandas as pd`` ``def export_to_excel(file_info):` `# 将元组列表转换为字典列表` `data = {` `'new_name': [],` `'new_sumBox': [],` `'new_box': [],` `'new_boxRate': [],` `'new_showRate': [],` `'new_seatRate': []` `}`` ` `for item in file_info:` `new_name, new_sumBox, new_box, new_boxRate, new_showRate, new_seatRate = item` `data['new_name'].append(new_name)` `data['new_sumBox'].append(new_sumBox)` `data['new_box'].append(new_box)` `data['new_boxRate'].append(new_boxRate)` `data['new_showRate'].append(new_showRate)` `data['new_seatRate'].append(new_seatRate)`` ` `# 创建一个DataFrame` `df = pd.DataFrame(data)`` ` `# 将DataFrame保存为xlsx文件` `df.to_excel('output.xlsx', index=False)
图6 转化为excel表格
三
可视化分析
接下来,根据爬取的票房数据绘制图表,直观地展示暑期票房情况。
import pandas as pd``import matplotlib.pyplot as plt``import re``file_excel = pd.read_excel('output.xlsx')
1.数据预处理
在分析之前需要对数据进行处理,读入表格并发现总票new_sumBox的数据类型为字符串,单位包括“万”和“亿”,应将其转化为统一单位以免绘制图表时出现问题。首先,使用正则表达式提取数字部分;然后,判断单位是“亿”时,将数字乘以1000转化为单位“万”,否则不进行转换。
# 定义函数进行单位换算``def convert_to_wan(value):` `pattern = r'(\d+(\.\d+)?)(亿|万)?'` `match = re.match(pattern, value)` `if match:` `number = float(match.group(1))` `unit = match.group(3)` `if unit == '亿':` `number *= 10000` `elif unit == '万':` `pass # 单位已经是“万”,不需要转换` `else:` `number /= 10000 # 默认单位是个位数,转换为“万”`` ` `return number` `else:` `return 0`` ``# 对new_sumBox列的值进行单位换算``file_excel['new_sumBox'] = file_excel['new_sumBox'].apply(convert_to_wan)``print(file_excel)
图7 对总票房数值进行单位换算
可以看出共有89部电影上映,为方便绘制图表,分别选取总票房和综合票房数前十的电影,绘制柱状图。其中,sumBox表示总票房为前十的dataframe,box表示综合票房为前十的dataframe。
# 选取前十``sumBox = file_excel.sort_values(by='new_sumBox', ascending=False).head(10)``box = file_excel.sort_values(by='new_box', ascending=False).head(10)
2.绘制总票房和综合票房图表
首先,引入库并定义需要绘制图形的数据,包括top10总票房、top10综合票房的电影名称、总票房数值、综合票房数值。
import random``from matplotlib.font_manager import FontProperties``from matplotlib.colors import Normalize`` ``# 定义需要绘制图形的数据``new_name_values1 = sumBox['new_name']``new_sumBox_values1 = sumBox['new_sumBox']``new_name_values2 = box['new_name']``new_box_values2 = box['new_box']
然后,设置支持中文的字体保证图形标签等能够正常显示;定义一组颜色,随机地赋给每个柱形;在每个柱形上添加对应的数值标注。
# 定义一个色系``color_palette = plt.cm.get_cmap('Blues', 20)` `colors = [color_palette(random.randint(0, 19)) for _ in new_name_values]`` ``# 设置中文字体``font = FontProperties(fname='Songti.ttc', size=12)` ` ``# 绘制柱状图``plt.figure(figsize=(10, 6))``bars = plt.bar(new_name_values1, new_sumBox_values1,color=colors)`` `` ``plt.xlabel('电影名称', fontproperties=font)``plt.ylabel('总票房,单位:万', fontproperties=font)``plt.title('总票房排名', fontproperties=font,size=18)``plt.xticks(rotation=30,fontproperties=font) # 使x轴标签倾斜以避免重叠`` ``# 添加数值标注``for bar in bars:` `height = bar.get_height()` `plt.text(bar.get_x() + bar.get_width() / 2, height, f'{height:.0f}', ha='center', va='bottom', fontproperties=font)`` ``plt.tight_layout()``plt.show()
图8 总票房top10
类似地,对于综合票房也绘制柱状图。
# 综合票房``# 定义一个色系``color_palette = plt.cm.get_cmap('Greens', 20)` `colors = [color_palette(random.randint(0, 19)) for _ in new_name_values]``# 绘制柱状图``plt.figure(figsize=(10, 6))``bars = plt.bar(new_name_values2, new_box_values2, color=colors)``plt.xlabel('电影名称', fontproperties=font)``plt.ylabel('综合票房,单位:万', fontproperties=font)``plt.title('综合票房排名', fontproperties=font,size=18)``plt.xticks(rotation=30,fontproperties=font) # 使x轴标签倾斜以避免重叠`` ``# 在每个柱状图上添加数值标注``for bar in bars:` `height = bar.get_height()` `plt.text(bar.get_x() + bar.get_width() / 2, height, f'{height}', ha='center', va='bottom', fontproperties=font)` `plt.tight_layout()``plt.show()
图9 综合票房top10
可以看出,截止到7月28日,《消失的她》总票房达到34.9亿元,并且在上映37天后,综合票房仍位列前10名。
图10 《消失的她》海报
从综合票房来看,《封神第一部》和《热烈》占据了大部分票房份额,吸引了大批观众涌入影院。且《热烈》上映了仅一天就获得了6837.81万元的票房。
3.绘制其他数据图表
接下来,绘制综合票房占比、排片占比、上座率的多数据系列柱状图,并创建第二个y轴,绘制综合票房为折线图。字体、颜色设置等和上述一致。
# 提取需要绘制的数据``new_name_values = box['new_name']``new_box_values = box['new_box']``new_boxRate_values = box['new_boxRate'].str.rstrip('%').astype(float)``new_showRate_values = box['new_showRate'].str.rstrip('%').astype(float)``new_seatRate_values = box['new_seatRate'].str.rstrip('%').astype(float)``# 设置中文字体``font = FontProperties(fname='Songti.ttc', size=12)` `# 定义一个色系``color_palette = plt.cm.get_cmap('Set3', 3)` `colors = [color_palette(i) for i in range(3)]`` ``# 绘制多数据系列柱状图``plt.figure(figsize=(10, 6))``bar_width = 0.2``index = range(len(new_name_values))`` ``plt.bar(index, new_boxRate_values, color=colors[0], width=bar_width, label='new_boxRate')``plt.bar([i + bar_width for i in index], new_showRate_values, color=colors[1], width=bar_width, label='new_showRate')``plt.bar([i + 2 * bar_width for i in index], new_seatRate_values, color=colors[2], width=bar_width, label='new_seatRate')`` ``plt.xlabel('电影名称', fontproperties=font)``plt.ylabel('百分比', fontproperties=font)``plt.title('综合票房top10数据', fontproperties=font,size=18)``plt.xticks([i + bar_width for i in index], new_name_values, rotation=30, fontproperties=font)``legend_labels = ['综合票房占比', '排片占比', '上座率', '综合票房']``plt.legend(labels=legend_labels, loc='upper right',prop=font)`` ``# 在每个柱状图上添加数值标注``for i in index:` `plt.text(i, new_boxRate_values[i], f'{new_boxRate_values[i]:.1f}', ha='center', va='bottom', fontproperties=font)` `plt.text(i + bar_width, new_showRate_values[i], f'{new_showRate_values[i]:.1f}', ha='center', va='bottom', fontproperties=font)` `plt.text(i + 2 * bar_width, new_seatRate_values[i], f'{new_seatRate_values[i]:.1f}', ha='center', va='bottom', fontproperties=font)`` ``# 绘制new_box列作为折线图``plt2 = plt.twinx() # 创建第二个y轴``plt2.plot(index, new_box_values, color='green', marker='o', label='综合票房')``plt2.set_ylabel('综合票房,单位:万', fontproperties=font)`` ``# 设置折线图的图例``plt2.legend(loc='upper right', bbox_to_anchor=(0.96, 0.8), prop=font)`` ``plt.tight_layout()``plt.show()
图11 综合票房top10数据
以上是基于selenium爬取猫眼实时票房的所有内容,大家可以探索使用scrapy框架等其他方式进行票房数据的爬取,也可以挑战猫眼票房专业版的动态字体加密。
对爬虫感兴趣的小伙伴,赠送全套Python学习资料,包含面试题、简历资料等具体看下方。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/371942?site
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。