目錄
一、設計方案
二、項目背景
三、電影爬蟲
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('
', '') # 電影名稱
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('
')[1].split('/')[0].strip()
year1 = movie_infos.split('
')[1].split('/')[1].strip()
year2 = movie_infos.split('
')[1].split('/')[2].strip()
year = year0 + '/' + year1 + '/' + year2
movie_year.append(year)
country = movie_infos.split('
')[1].split('/')[3].strip()
movie_country.append(country)
type = movie_infos.split('
')[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:[email protected]/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技術.
各平台搜索“”:知乎、哔哩哔哩、小紅書、新浪微博.