目录
一、项目背景
二、代码
三、总结
一、项目背景
(1)利用requests库采集豆瓣网分类排行榜 (“https://movie.douban.com/chart”)中各分类类别前100部电影的相关信息并存储为csv文件。
(2)利用获取的13个分类类别共1300部电影数据,获取电影所有上映国家并保存至csv文件。要求:其中index属性为国家或地区,columns属性为该国家发行电影的电影类型,值标识了各国家发行不同类型电影的数量信息。在表格的行尾和列尾分别加上属性“总计”,值为对应行、列的值加和;然后分别根据表格的index和columns“总计”进行从小到大排序。
(3)基于上述排序后的数据,选取发行电影数量最多的10个国家,选取电影类型最多的5个类型,使用matplotlib方法制作柱状堆叠图。其中横轴显示的国家,纵轴显示的电影数量,图例是各电影类别。
(4)分别获取13个分类类别对应的电影数量前7个国家,其他的用“其他”代替,计算每个分类类别对应的7个国家及“其他”部分的占比。使用matplotlib.pyplot.pie方法直观的显示这13个分类类别对应的国家发行电影数量占比,使用subplot方法进行多子图展示。
(5)计算获得所有电影的相似度(用欧式距离来定义),其中,DataFrame对象的index和columns均为所有的电影名称,值为两个电影的相似度。向每部电影推荐相似都最高的前5部电影。利用循环结构,循环提取每一部电影与其他所有电影的相似度数据,并进行排序,选择相似度最大(距离最近)的5部电影,同时将这5部电影的相似度记录下来。
二、代码
1、导入所需的Python包
#导包
import pandas as pd
import requests as rq
from bs4 import BeautifulSoup
import re
import numpy as np
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore", category=pd.errors.PerformanceWarning)
warnings.filterwarnings("ignore", category=pd.errors.SettingWithCopyWarning)
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 指定默认字体:解决plot不能显示中文问题
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
各模块功能如下:
pandas:用于数据处理和存储。
requests:用于发送HTTP请求。
BeautifulSoup:用于解析HTML内容。
re:用于正则表达式操作。
numpy:用于数值计算。
matplotlib.pyplot:用于绘图。
warnings:用于过滤警告信息。
pylab:用于设置图形显示的默认配置。
2、爬取豆瓣电影信息
通过requests读取包含电影信息的json,并将其转换为DataFrame。
#电影分类
movie_types = ['剧情','喜剧','动作','爱情','科幻','悬疑','惊悚','恐怖','历史','战争','犯罪','奇幻','冒险']
#设置requests headers,应对反爬机制
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'}def get_douban_movies():'''项目内容:利用 requests 库采集豆瓣网分类排行榜(“https://movie.douban.com/chart”)中各分类类别前 100 部电影的相关信息'''#豆瓣电影主页homepage = 'https://movie.douban.com/chart'#爬取主页web = rq.get(homepage,headers=headers)#设置中文编码web.encoding = 'utf-8'#解析HTMLsoup = BeautifulSoup(web.text,'lxml')#获取分类列表urls = [span.a['href'] for span in soup.select('div.types span')]require_urls = ['https://movie.douban.com'+u for movie_type in movie_types for u in urls if movie_type in u]#获取每个分类的数字编号numbers = [re.search(r'type=(\d+)', url).group(1) for url in require_urls]#数据存储到data列表data = []#遍历爬取13个分类counts = 0for number in numbers:url = 'https://movie.douban.com/j/chart/top_list?type={}&interval_id=100%3A90&action=&start=0&limit=100'.format(number)response = rq.get(url,headers=headers)#获取JSON数据data_json = response.json()#遍历100个电影for i in data_json:data.append([i['title'],i['release_date'],i['regions'],i['types'],i['url'],i['actors'],i['actor_count'],i['score'],i['vote_count'],i['types']])counts += 1print("成功爬取第{}个电影分类".format(counts))#将列表data转换为表格,配置列名df = pd.DataFrame(data,columns=['title','release_date','regions','types','film_url','actors','actor_count','score','vote_count','fenlei'])return df
3、统计各国家地区发行电影数量
def get_df_counties(df):#打散国家地区df = df.explode('regions')#创建空表格,后面再填充数据df_counties = pd.DataFrame()#遍历每一个电影分类for t in movie_types:df_counties[t] = df['types'].apply(lambda x:1 if t in x else 0)df_counties['regions'] = df['regions']#汇总df_counties = df_counties.groupby('regions').sum()df_counties['总计'] = df_counties.sum(axis=1)#计算行方向的统计count_list = []for t in movie_types+['总计']:count_list.append(df_counties[t].sum())df_counties.loc['总计'] = count_listprint('统计完成')return df_counties
4、绘制各国家地区分类电影堆叠图
def draw_bar_diagram(select_data):# 创建堆叠柱状图ax = select_data.plot.bar(stacked=True, figsize=(10, 6))# 添加标题和标签plt.title('各国家地区分类电影堆叠图')plt.xlabel('国家地区')plt.ylabel('电影数目')# 显示图形plt.savefig('各国家地区分类电影堆叠图.jpg')plt.show()
绘制图像如下:
5、绘制各国家地区发行电影数量占比图
def draw_pie_diagram(df_counties):df_counties = df_counties.drop('总计')#处理数据df_list = []for t in movie_types:df_sub = df_counties[t].nlargest(7)df_sub.loc['其他'] = df_counties.drop(df_sub.index)[t].sum()df_list.append(df_sub)# 设置子图布局fig, axes = plt.subplots(nrows=4, ncols=4, figsize=(10, 10))# 遍历每个电影类型的DataFramefor i, df in enumerate(df_list):# 将索引转换为整数类型#df.index = range(len(df))# 计算电影数量占比proportions = df / df.sum()# 绘制饼图ax = axes[i // 4, i % 4]ax.pie(proportions, labels=df.index, autopct='%1.1f%%', startangle=90)ax.set_title(df.name,fontdict={'fontsize': 20, 'color': 'black'}) # 使用电影类型作为子图标题#调整间距plt.subplots_adjust(wspace=0.5, hspace=2)#隐藏空白子图for i in range(len(df_list), 16):axes.flatten()[i].axis('off')plt.tight_layout()plt.savefig('各国家地区发行电影数量占比.jpg')# 显示图形plt.show()
绘制图像如下:
6、基于近邻规则生成推荐电影信息
def get_data_tuijian(df):df = df.drop_duplicates(subset='title', keep='first')#归一化df['score'] = (df['score'] - df['score'].min()) / (df['score'].max() - df['score'].min())df['vote_count'] = (df['vote_count'] - df['vote_count'].min()) / (df['vote_count'].max() - df['vote_count'].min())data = df[['title','score', 'vote_count']]#遍历每部电影,计算与其他电影的相似度for t in data.title.unique():col = data[data.title==t].iloc[0]sim_values = []for _ ,row in data.iterrows():sim_values.append(np.sqrt((row['score']-col['score'])**2+(row['vote_count']-col['vote_count'])**2))data[t] = sim_values#data[t] = (data[t] - data[t].min()) / (data[t].max() - data[t].min())#设置索引data.index=data.titledata = data.drop(columns=['title', 'score', 'vote_count'])data_tuijian = pd.DataFrame()data_tuijian['电影名称'] = data.indexdata_tuijian[['推荐电影1', '推荐电影2', '推荐电影3', '推荐电影4', '推荐电影5','与电影1相似度', '与电影2相似度', '与电影3相似度', '与电影4相似度', '与电影5相似度']] = None#遍历每一部电影,提取每一部电影的前5最相似电影for c in data.columns:top5 = data[c].sort_values().iloc[1:6].reset_index().valuesfor i in range(5):data_tuijian.loc[data_tuijian['电影名称']==c,'推荐电影'+str(i+1)] = top5[i][0]data_tuijian.loc[data_tuijian['电影名称']==c,'与电影{}相似度'.format(i+1)] = top5[i][1]print('推荐信息获取完成')return data_tuijian
7、主程序
if __name__ == '__main__':print('===========项目1、豆瓣电影信息爬取与存储==========')df = get_douban_movies()df.to_csv('film_info.csv',index=False,encoding='utf-8-sig')print('===========项目2、国家地区发行各类别电影的可视化分析==========')df_counties = get_df_counties(df)df_counties.to_csv('df_counties.csv',encoding='utf-8-sig')#绘制图表select_data = df_counties.sort_values(by='总计',ascending=False).iloc[:11]columns = select_data.iloc[0].sort_values(ascending=False).iloc[1:6].index.to_list()select_data = select_data[columns].iloc[1:] draw_bar_diagram(select_data)draw_pie_diagram(df_counties)print('===========项目3、基于近邻的电影推荐研究==========')df = pd.read_csv('film_info.csv')data_tuijian = get_data_tuijian(df)data_tuijian.to_csv('data_tuijian.csv',index=False,encoding='utf-8-sig')
三、总结
本项目主要考察的是对requests爬虫、pandas数据处理、matplotlib绘图等Python模块的使用,难度不大。