目标:
豆瓣电影爬虫系统:爬取豆瓣电影网站的数据,实现在网站上显示正在热映的10部电影(词云图)、评分最高的10部电影(散点图)以及主演电影数量最多的10位演员(条形图)的相关图形。
思维导图:
下面进行讲解:
电影爬虫:
1. 首先我们需要先导入模块和创建csv保存路径。
import re
import requests
import csv
from lxml import etree
import time
import os
# 定义文件路径
file_path = 'movies.csv'
with open(file_path, 'w', encoding='utf-8-sig') as f:
#指定了文件的编码为'utf-8-sig'以及不自动添加换行符(newline='')
writer = csv.writer(f, dialect='excel')
#'excel'是一个常用的格式,它使用逗号作为字段分隔符,双引号作为字段的包围字符,并处理包含逗号、换行符或双引号的字段。也可以注释,默认的足以使用。
writer.writerow(['电影名称', '电影评分', '电影排名', '导演', '主演', '电影海报地址', '上映日期', '电影国家', '电影类型'])
#使用writerow方法向CSV文件中写入一行数据,这里作为头部信息。
这里使用writerow方法向CSV文件中写入一行数据,后面的数据也保存到对应的列。
2.下面是请求豆瓣top250de1数据,
# 定义get请求函数
def get_page(url):
#定义请求头headers
try:
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
}
#发送get请求
res=requests. Get(url=url,headers=headers)
#判断请求是否成功
if res.status_code==200:
response=res.content.decode("utf-8")
return response
else:
return False
except:
return False
headers是请求头,可以通过谷歌来看,个人感觉比较清晰明了。
下面是对要爬取的数据进行正则化处理的具体代码:
#定义数据解析函数
def parse_data(html,url):
#数据解析一些内容有的需要xpath 有的需要正则
html = etree.HTML(html)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
}
res = requests.get(url=url, headers=headers)
response = res.content.decode("utf-8")
#电影名称
movie_title=html.xpath("//div[@class='hd']//a//span[1]//text()")
#电影评分
movie_score=html.xpath('//div[@class="star"]//span[2]//text()')
#电影排名
movie_degree=html.xpath('//div[@class="item"]//div//em//text()')
#电影海报地址
movie_poster=html.xpath('//div[@class="pic"]//a//img/@src')
#导演,使用正则
movie_director = re.findall(r"导演:(.*?);", response)
a = "".join(movie_director).split(" ")#因为使用的正则抓取下来的字符串含有 ,使用split()函数进行切分
movie_director = a[:25]
if movie_director=="":
movie_director=""
else:
movie_director=movie_director
#主演,使用正则
movie_main_act = re.findall("主演: (.*)<br>", response)
movie_main_act = "".join(movie_main_act).split("...")
if movie_main_act=="":
movie_main_act=""
else:
movie_main_act=movie_main_act
#上映日期
movie_datatime= re.findall(r"(\d*) ", response)
b = "".join(movie_datatime)#转化为字符串
movie_datatime = [b[i:i + 4] for i in range(0, len(b), 4)]#转换的字符串是一对数字如199419931994....,所以进行切分 4个一切就是年份
if movie_datatime=="":
movie_datatime=""
else:
movie_datatime=movie_datatime
#电影国家
movie_country= re.findall(" / (.*?) ", response)
movie_type= html.xpath("//div[@class='bd']/p/text()[2]")
n = ''.join([' '.join([i.strip() for i in price.strip().split('\n')]) for price in movie_type][::2]).split("\xa0/\xa0")#转换为字符串进行切分
l = n[2::2]#因为上面的n列表我们包含的电影类型,所以n[2::2]操作把包含类型都取出来
o = ''.join(l)#转换为字符串
h = re.sub("\d{4}", ";", o)#使用正则将数字全都用;符号代替
movie_type = h.lstrip("\n")#这个之前打印的最左边有一个\n符号 所以使用lstrip()函数去掉
movie_type = movie_type.split(";")#然后用字符串split()函数以;符号进行切分
if movie_type=="":
movie_type=""
else:
movie_type=movie_type
for a,b,c,d,e,f,g,h,i in list(zip(movie_title,movie_score,movie_degree,movie_director,
movie_main_act, movie_poster,movie_datatime,movie_country,movie_type)):
print(a,b,c,d,e,f,g,h,i)
# 写入
with open('movies.csv', 'a', encoding='utf-8-sig', newline='') as f:
writer = csv.writer(f, dialect='excel')
writer.writerow([a, b, c, d, e, f, g, h, i])
def main(num):
#定义url
url=f'https://movie.douban.com/top250?start={num}'
# 调用发送get请求函数
html=get_page(url)
# 如果发送请求成功,执行解析数据函数
if html:
parse_data(html,url)
运行结果:
python可视化大屏展示:
我是先将子图开发出来,然后用pyecharts的Page组件,把这些子图表拖拽组合起来,形成html大屏。
pyecharts
是一个用于生成各种图表的Python库,支持丰富的图表类型,包括饼图、柱状图、折线图等。
导入所需的:
from plotly.graph_objs import Bar
from pyecharts.charts import WordCloud, EffectScatter, Page, Pie
import pandas as pd
from pyecharts.charts import Bar
from pyecharts import options as opts
from pyecharts.globals import ThemeType
标题:
csv_file_path = 'your csv path' # 替换为你的CSV文件路径,我们刚刚生成的。
# 自定义HTML标题
folder = ''
def tab1(name, color): # 标题
c = (Pie(init_opts=opts.InitOpts(theme=ThemeType.CHALK)).
set_global_opts(
title_opts=opts.TitleOpts(title=name, pos_left='center', pos_top='center',
title_textstyle_opts=opts.TextStyleOpts(color=color, font_size=36))))
return c
注意:在这个tab1
函数中,c
是一个Pie
对象(来自于pyecharts
库),该对象代表了一个饼图(Pie chart)的配置和数据结构。通过链式调用set_global_opts
方法来设置全局配置项。
因为pyecharts组件没有专门用作标题的函数,所以直接运用Pie来实现标题的效果,没有添加数据。
运行结果:
条形图:
def create_actor_bar_chart(csv_file_path): #条形图
# 读取CSV文件
movie_data = pd.read_csv(csv_file_path, encoding='utf-8')
# 统计演员的作品数量
actor_counts = movie_data.iloc[:, 4].value_counts() # 假设第五列是演员名称
top_actors = actor_counts.head(10) # 获取作品数量前十的演员
# 准备数据
actors = top_actors.index.tolist()
counts = top_actors.values.tolist()
# 创建 Bar 对象
bar = (
Bar(
init_opts=opts.InitOpts(theme=ThemeType.CHALK)
)
.add_xaxis(actors)
.add_yaxis("作品数量", counts)
.set_global_opts(
title_opts=opts.TitleOpts(title="主演电影数量最多的10位演员", pos_left='center'),
xaxis_opts=opts.AxisOpts(name="演员", axislabel_opts=opts.LabelOpts(rotate=45)),
yaxis_opts=opts.AxisOpts(name="作品数量"),
legend_opts=opts.LegendOpts(is_show=False),
)
.set_series_opts(
label_opts=opts.LabelOpts(is_show=True, position="inside", color="#fff"),
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max", name="最大值")]),
)
)
return bar
因为求主演电影数量最多的10位演员(以条形图)的形式展示出来,所以需要actors和counts的对应数据,然后才能创建Bar对象,因为演员名字有较长还定义了markpoint_opts(用于高亮显示数据中的最大值)。
运行结果:
散点图:
#生成散点图
def create_movie_scatter_chart(csv_file_path):
# 读取CSV文件
try:
movie_data = pd.read_csv(csv_file_path, encoding='utf-8')
except FileNotFoundError:
print(f"文件未找到: {csv_file_path}")
return None
# 获取前十个电影名称和评分
top_movies = movie_data.head(10)[['电影名称', '电影评分']].values.tolist()
# 检查top_movies是否为空
if not top_movies:
print("没有有效数据,无法生成散点图")
return None
# 创建散点图
sc = EffectScatter(init_opts=opts.InitOpts(width="600px", height="400px",theme=ThemeType.CHALK))
# 提取电影名称和评分,准备添加到图表中
x_data, y_data = zip(*top_movies)
# 添加数据到图表
sc.add_xaxis(x_data) # 电影名称
sc.add_yaxis("电影评分", y_data, symbol_size=10, label_opts=opts.LabelOpts(is_show=False)) # 电影评分
# 设置X轴和Y轴
xaxis_opts = opts.AxisOpts(
type_="category",
name="电影名称",
axislabel_opts=opts.LabelOpts(rotate=45) # 调整标签旋转角度以便更好地显示
)
yaxis_opts = opts.AxisOpts(
name="电影评分",
type_="value"
)
# 设置全局选项
sc.set_global_opts(
title_opts=opts.TitleOpts(title='评分最高的10部电影'),
xaxis_opts=xaxis_opts,
yaxis_opts=yaxis_opts,
tooltip_opts=opts.TooltipOpts(is_show=False),
)
return sc
同样需要先准备数据,然后创建对象。
运行结果:
词云图:
# 定义一个函数来生成词云图
def filmname_wordcloud(csv_file_path):
# 读取CSV文件
df = pd.read_csv(csv_file_path)
print(df['电影名称'])
data = df['电影名称'].value_counts(30).head(600) # 取最常见的词
#设置图表初始化选项的一种方式。
#init_opts参数通常作为图表类(如Pie、Bar、Line等)的构造函数的一个参数来传递。
# 创建词云图实例
wc = WordCloud(init_opts=opts.InitOpts(width="450px", height="350px",theme=ThemeType.CHALK))
# 添加词云图数据
# 假设每个词的出现都是一次,创建数据对
wc.add(series_name="电影名称",
data_pair=list(zip(data.index.tolist(), data.tolist())), # 将Series转换为数据对列表
word_size_range=[15, 60], # 根据需要调整单词字体大小范围
width='400px', # 宽度
height='300px', # 高度
word_gap=1 # 单词间隔
)
# 设置全局配置项
wc.set_global_opts(
title_opts=opts.TitleOpts(pos_left='all',
title="正在热映的10部电影",
title_textstyle_opts=opts.TextStyleOpts(font_size=18)
),
tooltip_opts=opts.TooltipOpts(is_show=False) # 显示提示框
)
return wc
运行结果:
Page拖拽组合:
上面我们已经生成了词云图,散点图,条形图以及标题(饼图),下面我们通过
layout=Page.DraggablePageLayout组合起来,并且导入实参。
page = Page(page_title="基于Python的电影数据分析大屏",
layout=Page.DraggablePageLayout)
page.add(
tab1("数据可视化大屏", "black"),
create_movie_scatter_chart(csv_file_path),
create_actor_bar_chart(csv_file_path),
filmname_wordcloud(csv_file_path))
page. Render("test.html")
代码执行后,会生成一个test,html的可拖拽页面,可以自由组合自己喜欢的排列方式。
注意,页面的左上角会有一个小小的图标。
排列好后,点击它,会生成一个json,里面是配置的位置信息。
执行新建的py文件,会生成最终的html页面(不可拖拽)。
最终运行结果:
我这里为了符合题意采用的数据较少,可以修改对应的参数来增加美观。
这里我引用了的一些想法和思路,如有侵权请联系我,谢谢。【Python可视化大屏】全流程讲解pyecharts拖拽可视化大屏的背后原理_python 可视化拖拉拽-CSDN博客