Python爬取暑期票房排行
本文作者:智淼 中南财经政法大学统计与数学学院
本文编辑:董高飞
技术总编:金点
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 猫眼电影实时票房专业版网页
观察源码和网页内显示的内容是否一致。在源码中找到名为<tbody class="table-body">的HTML标签,依次展开,发现网页呈现出的内容和源码一致。但在使用requests库请求该地址时发现得到的数据并不完整,这是因为该网页使用了异步加载方式。因此,接下来考虑使用selenium库。
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元素定位并获取元素。
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)
#输出为表格
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)
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)
# 选取前十
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()
类似地,对于综合票房也绘制柱状图。
# 综合票房
# 定义一个色系
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()
可以看出,截止到7月28日,《消失的她》总票房达到34.9亿元,并且在上映37天后,综合票房仍位列前10名。
接下来,绘制综合票房占比、排片占比、上座率的多数据系列柱状图,并创建第二个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框架等其他方式进行票房数据的爬取,也可以挑战猫眼票房专业版的动态字体加密。
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:让数学公式输入更方便!
处理日期的好手:pendulumWhat’ new ? 速通Stata 18
关于我们微信公众号“Stata and Python数据分析”分享实用的Stata、Python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。
武汉字符串数据科技有限公司一直为广大用户提供数据采集和分析的服务工作,如果您有这方面的需求,请发邮件到statatraining@163.com,或者直接联系我们的数据中台总工程司海涛先生,电话:18203668525,wechat: super4ht。海涛先生曾长期在香港大学从事研究工作,现为知名985大学的博士生,爬虫俱乐部网络爬虫技术和正则表达式的课程负责人。
此外,欢迎大家踊跃投稿,介绍一些关于Stata和Python的数据处理和分析技巧。
爬虫俱乐部