查看原文
其他

Python爬取暑期票房排行

爬虫俱乐部 Stata and Python数据分析 2023-10-24

本文作者:智淼 中南财经政法大学统计与数学学院

本文编辑:董高飞

技术总编:金点








Stata and Python 数据分析

爬虫俱乐部Stata基础课程Stata进阶课程Python课程可在小鹅通平台查看,欢迎大家多多支持订阅!如需了解详情,可以通过课程链接(https://appbqiqpzi66527.h5.xiaoeknow.com/homepage/10)或课程二维码进行访问哦~

每至暑期,电影市场都会掀起一波又一波的高潮,众多佳片在这个黄金档期相继上映,面临着激烈的票房争夺战。猫眼电影是美团旗下的一站式电影互联网平台,占据网络购票市场份额的40%以上,本文将基于selenium爬取猫眼实时票房网站,获取暑期综合票房、排片占比、排座占比等信息,并进行可视化分析。

网页分析

爬取的目标网页为猫眼电影实时票房常规版(https://piaofang.maoyan.com/box-office?ver=normal),选择该网页而不是专业版(https://piaofang.maoyan.com/dashboard)是因为专业版网页爬取难度较大。查看源码,可以看到在专业版网页中,综合票房显示为一段div包裹的不可见文本。对于常规版网页来说,票房数字在源码中正常显示,因此本文将爬取猫眼电影实时票房常规版网页的内容。

图1 猫眼电影实时票房专业版网页

图2 猫眼电影实时票房常规版网页

观察源码和网页内显示的内容是否一致。在源码中找到名为<tbody class="table-body">HTML标签,依次展开,发现网页呈现出的内容和源码一致。但在使用requests库请求该地址时发现得到的数据并不完整,这是因为该网页使用了异步加载方式。因此,接下来考虑使用selenium库。

图3 观察源码
提取信息
首先引入库,使用webdriver进入页面。注意:在使用selunium之前要下载对应浏览器版本的webDriver驱动,解压后的存放路径为:浏览器的根目录下(windows)、/usr/local/bin/(macos、linux)。本文使用的是chrome浏览器:
from selenium import webdriverfrom selenium.webdriver.common.by import Bydriver = 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 pdimport matplotlib.pyplot as pltimport refile_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 randomfrom matplotlib.font_manager import FontPropertiesfrom 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.2index = 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框架等其他方式进行票房数据的爬取,也可以挑战猫眼票房专业版的动态字体加密。













END













重磅福利!为了更好地服务各位同学的研究,爬虫俱乐部将在小鹅通平台上持续提供金融研究所需要的各类指标,包括上市公司十大股东、股价崩盘、投资效率、融资约束、企业避税、分析师跟踪、净资产收益率、资产回报率、国际四大审计、托宾Q值、第一大股东持股比例、账面市值比、沪深A股上市公司研究常用控制变量等一系列深加工数据,基于各交易所信息披露的数据利用Stata在实现数据实时更新的同时还将不断上线更多的数据指标。我们以最前沿的数据处理技术、最好的服务质量、最大的诚意望能助力大家的研究工作!相关数据链接,请大家访问:(https://appbqiqpzi66527.h5.xiaoeknow.com/homepage/10)或扫描二维码:


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







往期推文推荐给文件搬家——copy&XCOPYNLTK,全面的Python基础NLP库
爬取A股上市公司指定年份年报
机器学习——监督学习入门‍‍禁忌魔法解封,击穿专业壁垒:ChatGPT code interpreter暑期来啦~⼀起看⼀看近期的天⽓情况【命令重磅更新】在Stata中深入使用ChatGPT
爬虫俱乐部2023第一期编程训练营开始报名啦!
【爬虫基础】Scrapy爬虫框架迈向交互式编程,ChatGPT更新!一个简单又好玩的Python库——MyQR
replace命令的“加强版”!——如何使用ereplace,结合egen
XML 轻松读取:用 Python 发现数据宝藏

爬虫俱乐部重磅推出cnstata.com.cn

Markdown:让数学公式输入更方便!

处理日期的好手:pendulum
定制属于自己的“贾维斯”——Python调用Chat
学会format,数据格式任你拿捏【Python实战】游客最青睐的城市,你的家乡上榜了吗?

What’ new ? 速通Stata 18

     关于我们 

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

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



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

投稿邮箱:statatraining@163.com投稿要求:1)必须原创,禁止抄袭;2)必须准确,详细,有例子,有截图;注意事项:1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。

爬虫俱乐部

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

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