目录
一、设计方案
二、项目背景
三、电影爬虫
3.1 导入库
3.2 发送请求
3.3 解析页面
3.4 存储到csv
四、数据持久化存储
4.1 导入库
4.2 存入MySQL
4.3 讲解视频
五、开发可视化大屏
5.1 柱形图
5.2 饼图
5.3 词云图
5.4 数据表格
5.5 涟漪散点图
5.6 条形图
5.7 大标题
5.8 Page组合
六、彩蛋-多种主题
6.1 CHALK主题
6.2 PURPLE主题
6.3 ESSOS主题
6.4 ROMANTIC主题
6.5 DARK主题
七、拖拽演示视频
八、讲解视频
“整篇文章较长,干货很多!建议收藏后,分章节阅读。”
整篇文章,也将按照这个结构来讲解。
若有重点关注部分,可点击章节目录直接跳转!
针对某电影TOP250排行榜的数据,开发一套可视化数据大屏系统,展示各维度数据分析结果。
import requests # 发送请求
from bs4 import BeautifulSoup # 解析网页
import pandas as pd # 存取csv
from time import sleep # 等待时间
from sqlalchemy import create_engine # 连接数据库
定义一些空列表,用于临时存储爬取下的数据
movie_name = [] # 电影名称
movie_url = [] # 电影链接
movie_star = [] # 电影评分
movie_star_people = [] # 评分人数
movie_director = [] # 导演
movie_actor = [] # 主演
movie_year = [] # 上映年份
movie_country = [] # 国家
movie_type = [] # 类型
short_comment = [] # 一句话短评
向页面发送请求:
res = requests.get(url, headers=headers)
利用BeautifulSoup库解析响应页面:
soup = BeautifulSoup(res.text, 'html.parser')
用BeautifulSoup的select函数,(css解析的方法)编写代码逻辑,部分核心代码:
for movie in soup.select('.item'):
name = movie.select('.hd a')[0].text.replace('\n', '') # 电影名称
movie_name.append(name)
url = movie.select('.hd a')[0]['href'] # 电影链接
movie_url.append(url)
star = movie.select('.rating_num')[0].text # 电影评分
movie_star.append(star)
star_people = movie.select('.star span')[3].text # 评分人数
star_people = star_people.strip().replace('人评价', '')
movie_star_people.append(star_people)
其中,需要说明的是,《大闹天宫》这部电影和其他电影页面排版不同:
它的上映年份有3个(其他电影只有1个上映年份),并且以"/"分隔,正好和国家、电影类型的分割线冲突,
所以,这里特殊处理一下:
if name == '大闹天宫 / 大闹天宫 上下集 / The Monkey King': # 大闹天宫,特殊处理
year0 = movie_infos.split('\n')[1].split('/')[0].strip()
year1 = movie_infos.split('\n')[1].split('/')[1].strip()
year2 = movie_infos.split('\n')[1].split('/')[2].strip()
year = year0 + '/' + year1 + '/' + year2
movie_year.append(year)
country = movie_infos.split('\n')[1].split('/')[3].strip()
movie_country.append(country)
type = movie_infos.split('\n')[1].split('/')[4].strip()
movie_type.append(type)
最后,将爬取到的数据保存到csv文件中:
def save_to_csv(csv_name):
"""
数据保存到csv
:return: None
"""
df = pd.DataFrame() # 初始化一个DataFrame对象
df['电影名称'] = movie_name
df['电影链接'] = movie_url
df['电影评分'] = movie_star
df['评分人数'] = movie_star_people
df['导演'] = movie_director
df['主演'] = movie_actor
df['上映年份'] = movie_year
df['国家'] = movie_country
df['类型'] = movie_type
df.to_csv(csv_name, encoding='utf_8_sig') # 将数据保存到csv文件
然后,就可以把csv数据导入到MySQL数据库,做持久化存储了。
import pandas as pd # 存取csv
from sqlalchemy import create_engine # 连接数据库
最核心的三行代码:
# 把csv导入mysql数据库
engine = create_engine('mysql+pymysql://root:123456@localhost/db_bigscreen')
df = pd.read_csv('Movie250.csv')
df.to_sql(name='t_film', con=engine, chunksize=1000, if_exists='replace', index=None)
用create_engine创建数据库连接,格式为:
create_engine('数据库类型+数据库驱动://用户名:密码@数据库IP地址/数据库名称')
这样,数据库连接就创建好了。
然后,用pandas的read_csv函数读取csv文件。
最后,用pandas的to_sql函数,把数据存入MySQL数据库:
name='college_t2' #mysql数据库中的表名
con=engine # 数据库连接
index=False #不包含索引字段
if_exists='replace' #如果表中存在数据,就替换掉,另外,还支持append(追加数据)
非常方便地完成了反向导入,即:从csv向数据库的导入。
同步讲解视频:
仅用Python三行代码,实现数据库和excel之间导入导出
如文章开头的思维导图所说,首先把各个子图表开发出来,然后用pyecharts的Page组件,把这些子图表拼装组合起来,形成大屏。
下面,依次讲解每个子图表的实现。
pyecharts官网-柱形图: A Python Echarts Plotting Library built with love.
因为需要实现分段区间统计,所以先定义出一个区间对象:
# 设置分段
bins = [0, 100000, 200000, 300000, 500000, 1000000, 3000000]
# 设置标签
labels = ['0-10w', '10w-20w', '20w-30w', '30w-50w', '50w-100w', '100w-300w']
然后,对数据进行按段切割,并统计个数:
# 按分段离散化数据
segments = pd.cut(cmt_count_list, bins, labels=labels) # 按分段切割数据
counts = pd.value_counts(segments, sort=False).values.tolist() # 统计个数
最后,采用pyecharts里的Bar对象,画出柱形图:
bar = Bar(
init_opts=opts.InitOpts(theme=theme_config, width="450px", height="350px", chart_id='bar_cmt2')) # 初始化条形图
bar.add_xaxis(labels, ) # 增加x轴数据
bar.add_yaxis("评价数", counts) # 增加y轴数据
bar.set_global_opts(
legend_opts=opts.LegendOpts(pos_left='right'),
title_opts=opts.TitleOpts(title="评价数量区间分布-柱形图", pos_left='center'), # 标题
toolbox_opts=opts.ToolboxOpts(is_show=False, ), # 不显示工具箱
xaxis_opts=opts.AxisOpts(name="评论数", # x轴名称
axislabel_opts=opts.LabelOpts(font_size=8)), # 字体大小
yaxis_opts=opts.AxisOpts(name="电影数量",
axislabel_opts={"rotate": 0},
splitline_opts=opts.SplitLineOpts(is_show=True,
linestyle_opts=opts.LineStyleOpts(type_='solid')),
), # y轴名称
)
# 标记最大值
bar.set_series_opts(
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max", name="最大值"), ],
symbol_size=35) # 标记符号大小
)
bar.render("评价数分布-柱形图.html") # 生成html文件
print('生成完毕:评价数分布-柱形图.html')
图表效果:
pyecharts官网-饼图: A Python Echarts Plotting Library built with love.
绘制情感分布的饼图。所以,首先要对评价数据进行情感分析。
鉴于电影评价内容都是中文文本设计,情感分析采用snownlp技术进行。
score_list = [] # 情感评分值
tag_list = [] # 打标分类结果
pos_count = 0 # 计数器-积极
mid_count = 0 # 计数器-中性
neg_count = 0 # 计数器-消极
for comment in v_cmt_list:
tag = ''
sentiments_score = SnowNLP(comment).sentiments
if sentiments_score < 0.4: # 情感分小于0.4判定为消极
tag = '消极'
neg_count += 1
elif 0.4 <= sentiments_score <= 0.6: # 情感分在[0.4,0.6]直接判定为中性
tag = '中性'
mid_count += 1
else: # 情感分大于0.6判定为积极
tag = '积极'
pos_count += 1
score_list.append(sentiments_score) # 得分值
tag_list.append(tag) # 判定结果
df['情感得分'] = score_list
df['分析结果'] = tag_list
df.to_excel('情感判定结果.xlsx', index=None) # 把情感分析结果保存到excel文件
按照情感得分值划分区间:
最终将结果保存到Excel文件中,查看下:
将此结果中的数据,带入到Pie组件中,画出饼图:
# 画饼图
pie = (
Pie(init_opts=opts.InitOpts(theme=theme_config, width="450px", height="350px", chart_id='pie1'))
.add(series_name="评价情感分布", # 系列名称
data_pair=[['积极', pos_count], # 添加数据
['中性', mid_count],
['消极', neg_count]],
rosetype="radius", # 是否展示成南丁格尔图
radius=["30%", "55%"], # 扇区圆心角展现数据的百分比,半径展现数据的大小
) # 加入数据
.set_global_opts( # 全局设置项
title_opts=opts.TitleOpts(title="短评情感分布-饼图", pos_left='center'), # 标题
legend_opts=opts.LegendOpts(pos_left='right', orient='vertical') # 图例设置项,靠右,竖向排列
)
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))) # 样式设置项
pie.render('情感分布_饼图.html') # 生成html文件
print('生成完毕:情感分布_饼图.html')
图表效果:
pyecharts官网-词云图: A Python Echarts Plotting Library built with love.
针对TOP250的电影名称,绘制出词云图。
先对数据做清洗操作,然后直接画出词云图即可:
wc = WordCloud(init_opts=opts.InitOpts(width="450px", height="350px", theme=theme_config, chart_id='wc1'))
wc.add(series_name="电影名称",
data_pair=data,
word_size_range=[15, 20],
width='400px', # 宽度
height='300px', # 高度
word_gap=5 # 单词间隔
) # 增加数据
wc.set_global_opts(
title_opts=opts.TitleOpts(pos_left='center',
title="电影名称分析-词云图",
title_textstyle_opts=opts.TextStyleOpts(font_size=20) # 设置标题
),
tooltip_opts=opts.TooltipOpts(is_show=True), # 不显示工具箱
)
wc.set_series_opts(label_opts=opts.LabelOpts(is_show=True))
wc.render('电影名称_词云图.html') # 生成html文件
print('生成完毕:电影名称_词云图.html')
图表效果:
pyecharts官网-表格: A Python Echarts Plotting Library built with love.
把排名前10的电影详情数据,展现到大屏上,采用pyecharts里的Table组件实现。
从MySQL数据库读取到数据后,直接进行绘制表格:
table = (
Table(page_title='我的表格标题', )
.add(headers=['排名', '电影名称', '评分', '评论数', '上映年', '一句话短评'], rows=data_list, attributes={
"align": "left",
"border": False,
"padding": "20px",
"style": "background:{}; width:450px; height:350px; font-size:10px; color:#C0C0C0;padding:3px;".format(
table_color)
})
.set_global_opts(title_opts=opts.TitleOpts(title='这是表格1'))
)
table.render('电影排名TOP10_数据表格.html')
print('生成完毕:电影排名TOP10_数据表格.html')
图表效果:
pyecharts官网-涟漪散点图: A Python Echarts Plotting Library built with love.
针对电影的上映年份和评分值,两个纬度的数据,绘制出涟漪散点图(涟漪散点图和普通散点图的区别,就是涟漪散点图是动态图,图上的每个点都在闪烁,像水面上的涟漪一样)。
sc = (EffectScatter(init_opts=opts.InitOpts(width="450px", height="350px", theme=theme_config, chart_id='scatter1'))
.add_xaxis(xaxis_data=x_data)
.add_yaxis(
series_name="",
y_axis=y_data,
symbol_size=10,
label_opts=opts.LabelOpts(is_show=False),
)
.set_series_opts()
.set_global_opts(
# 忽略部分代码
)
)
sc.render('评分年份分布-散点图.html')
print('生成完毕:散点图.html')
图表效果(截图是png,其实小圆点是在闪烁的):
pyecharts官网-条形图: A Python Echarts Plotting Library built with love.
针对评论数最多的10个电影的评论作者,绘制出横向条形图。
# 画条形图
bar = Bar(
init_opts=opts.InitOpts(theme=theme_config, width="450px", height="350px", chart_id='bar_cmt1')) # 初始化条形图
bar.add_xaxis(x_data) # 增加x轴数据
bar.add_yaxis("评论数量", y_data) # 增加y轴数据
bar.reversal_axis() # 设置水平方向
bar.set_series_opts(label_opts=opts.LabelOpts(position="right")) # Label出现位置
bar.set_global_opts(
legend_opts=opts.LegendOpts(pos_left='right'),
title_opts=opts.TitleOpts(title="评论数TOP10作者-条形图", pos_left='center'), # 标题
toolbox_opts=opts.ToolboxOpts(is_show=False, ), # 不显示工具箱
xaxis_opts=opts.AxisOpts(name="评论", # x轴名称
axislabel_opts=opts.LabelOpts(font_size=8, rotate=0),
splitline_opts=opts.SplitLineOpts(is_show=False)
),
yaxis_opts=opts.AxisOpts(name="电影", # y轴名称
axislabel_opts=opts.LabelOpts(font_size=7, rotate=45), # y轴名称
)
)
bar.render("评论数TOP10_条形图.html") # 生成html文件
print('生成完毕:评论数TOP10_条形图.html')
图表效果:
由于pyecharts组件没有专门用作标题的图表,我决定灵活运用Table组件实现大标题。即,让Table只有标题header,没有数据行row,再针对header做一些样式调整(字体增大等),即可实现一行大标题。
table = Table()
table.add(headers=[v_title], rows=[], attributes={
"align": "center",
"border": False,
"padding": "2px",
"style": "background:{}; width:1350px; height:50px; font-size:25px; color:#C0C0C0;".format(table_color)
})
table.render('大标题.html')
print('生成完毕:大标题.html')
图表效果:
最后,也是最关键的一步,把以上所有图表组合到一起,用Page组件,并且选用DraggablePageLayout方法,即拖拽的方式,组合图表:
# 绘制:整个页面
page = Page(
page_title="基于Python的电影数据分析大屏",
layout=Page.DraggablePageLayout, # 拖拽方式
)
page.add(
# 增加:大标题
make_title(v_title='基于Python的电影数据分析大屏'),
# 绘制:中下方数据表格
make_table(v_df=df_table),
# 绘制:电影名称词云图
filmname_wordcloud(v_str=film_all_list),
# 绘制:TOP10评论数-条形图
make_top10_comment_bar(v_df=df),
# 绘制情感分布饼图
make_analyse_pie(v_cmt_list=comment_all_list),
# 绘制:评价数分段统计-柱形图
make_cmt_count_bar(v_df=df),
# 绘制:散点图
make_scatter(x_data=year_list, y_data=score_list)
)
page.render('大屏_临时.html') # 执行完毕后,打开临时html并排版,排版完点击Save Config,把json文件放到本目录下
print('生成完毕:大屏_临时.html')
本代码执行完毕后,打开临时html并排版,排版完点击Save Config,把json文件放到本目录下。
再执行最后一步,调用json配置文件,生成最终大屏文件。
# 执行之前,请确保:1、已经把json文件放到本目录下 2、把json中的title和table的id替换掉
Page.save_resize_html(
source="大屏_临时.html",
cfg_file="chart_config.json",
dest="大屏_最终_0426.html"
)
拖拽过程的演示视频:
【Python可视化大屏】用pyecharts拖拽生成大屏!
至此,所有代码执行完毕,生成了最终大屏html文件。
为了实现不同颜色主题的大屏可视化效果,我开发了一个实现逻辑,只需修改一个参数,即可展示不同颜色主题。
# 全局设置主题颜色
theme_config = ThemeType.CHALK # 颜色方案
由于Table组件是不能设置颜色主题的,所以我手写了一个逻辑(用取色器获取的RGB值,又转成十六进制的颜色!),如下:
# 表格和标题的颜色
table_color = ""
if theme_config == ThemeType.DARK:
table_color = '#333333'
elif theme_config == ThemeType.CHALK:
table_color = '#293441'
elif theme_config == ThemeType.PURPLE_PASSION:
table_color = '#5B5C6E'
elif theme_config == ThemeType.ROMANTIC:
table_color = '#F0E8CD'
elif theme_config == ThemeType.ESSOS:
table_color = '#FDFCF5'
else:
table_color = ''
最终实现了多种颜色主题,包含以下。
通过5种主题颜色,展示同一个大屏效果,有被炫到嘛?
拖拽过程演示视频:
【Python可视化大屏】用pyecharts拖拽生成大屏!
【Python大屏教程】全流程揭秘!讲解可视化大屏背后原理
首发公众号文章:【Python可视化大屏】全流程揭秘实现可视化数据大屏的背后原理!
我是马哥,全网累计粉丝上万,欢迎一起交流python技术。
各平台搜索“马哥python说”:知乎、哔哩哔哩、小红书、新浪微博。