爬取豆瓣电影数据并进行分析可视化

学习爬虫爬取豆瓣电影数据并进行分析,整体流程如下:

1、爬取豆瓣电影数据

2、读取豆瓣电影数据

3、统计各个电影的评论数

4、读取某个电影的全部评论内容

5、获取某个电影的关键词并生成词云图

6、对电影数据的关键词和评分进行辩证分析并生成热力图

让我们开始吧!废话不多说,直接上代码 #------#

爬取豆瓣电影数据

import requests
from bs4 import BeautifulSoup
from collections import OrderedDict
import pandas as pd
# 设定headers
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
movie_info = OrderedDict()

def detail_handle(url):
    html = requests.get(url,headers = headers)
    soup = BeautifulSoup(html.text,'lxml')
    movie_info['movie_rank'] = soup.find_all('span',class_="top250-no")[0].string
    movie_info['movie_name'] = soup.find_all('span',property="v:itemreviewed")[0].string
    soup_div = soup.find(id="info")
    movie_info['movie_director'] = handle_mul_tags(soup_div.find_all('span')[0].find_all('a'))
    movie_info['movie_writer'] = handle_mul_tags(soup_div.find_all('span')[3].find_all('a'))
    movie_info['movie_starring'] = handle_mul_tags(soup_div.find_all('span')[6].find_all('a'))
    movie_info['movie_type'] = handle_mul_tags(soup_div.find_all('span',property="v:genre"))
    movie_info['movie_country'] = soup_div.find(text = '制片国家/地区:').next_element.lstrip().rstrip()
    movie_info['movie_language'] = soup_div.find(text = '语言:').next_element.lstrip().rstrip()
    movie_info['movie_release_date'] = handle_mul_tags(soup_div.find_all('span',property="v:initialReleaseDate"))
    movie_info['movie_run_time'] = handle_mul_tags(soup_div.find_all('span',property="v:runtime"))
    movie_second_name = ''
    try:
        movie_info['movie_second_name'] = soup_div.find(text = '又名:').next_element.lstrip().rstrip()
    except AttributeError:
        print('{}没有别名'.format(movie_info['movie_name']))
        movie_info['movie_second_name'] = movie_second_name
        
    movie_info['movie_rating'] = soup.find_all('strong',property="v:average")[0].string
    movie_info['movie_comment_users'] = soup.find_all('span',property="v:votes")[0].string
    soup_div_for_ratings = soup.find('div',class_="ratings-on-weight")
    movie_info['movie_five_star_ratio'] = soup_div_for_ratings.find_all('div')[0].find(class_="rating_per").string
    movie_info['movie_four_star_ratio'] = soup_div_for_ratings.find_all('div')[2].find(class_="rating_per").string
    movie_info['movie_three_star_ratio'] = soup_div_for_ratings.find_all('div')[4].find(class_="rating_per").string
    movie_info['movie_two_star_ratio'] = soup_div_for_ratings.find_all('div')[6].find(class_="rating_per").string
    movie_info['movie_one_star_ratio'] = soup_div_for_ratings.find_all('div')[8].find(class_="rating_per").string
    return movie_info
    
def handle_mul_tags(soup_span): # 获取多个标签结果将合并在一起,以/分隔
    info = ''
    for second_span in soup_span:
        info = ('' if (info == '') else '/').join((info,second_span.string))
    return info

def crawl():
    htmls = ['https://movie.douban.com/top250?start={}&filter='.format(str(page)) for page in range(0,250,25)]
    for html in htmls:
        html_url = requests.get(html,headers = headers)
        soup = BeautifulSoup(html_url.text,'lxml')
        movie_htmls = soup.select('.pic')
        for movie_html in movie_htmls:
            url = movie_html.select('a')[0]['href']
            return detail_handle(url)

对电影数据进行分析和可视化

import sqlite3
import pandas as pd
import jieba
import math
import pyecharts.options as opts
from pyecharts.charts import WordCloud
import os
os.chdir('C:\\Users\\Theo.chen\\Desktop\\数据分析项目\\')

import matplotlib as mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

conn = sqlite3.connect('douban_comment_data.db')
comment_data = pd.read_sql_query('select * from comment;', conn)
movie_data = pd.read_excel('douban_movie_data.xlsx')
FILTER_WORDS = ['知道','影评','影片','小编','没有','一个','\n','good','is','thing','这个','就是','什么','真的','of',
                '我们','最后','一部','the','片子','这么','那么','不是','还是','时候','觉得','电影','但是','hope','Hope','best','因为',
                '只是','故事','看过','豆瓣','maybe','这部']

def get_movie_idList(min_comment_count):
    movie_list = comment_data['MOVIEID'].value_counts()
    movie_list = movie_list[movie_list.values > min_comment_count]  
# 筛选出评论数>100的电影
    return movie_list.index

def get_comment_keywords(movie_id,count):
    comment_list = comment_data[comment_data['MOVIEID'] == movie_id]['CONTENT']
    comment_str_all = ''
    for comment in comment_list:
        comment_str_all += comment + '\n'
    seg_list = list(jieba.cut(comment_str_all))
    keywords_counts = pd.Series(seg_list)
    keywords_counts = keywords_counts[keywords_counts.str.len() > 1]
    keywords_counts = keywords_counts[~keywords_counts.str.contains('|'.join(FILTER_WORDS))]
    keywords_counts = keywords_counts.value_counts()[:count]
    return keywords_counts

def get_movie_name_and_score(movie_id):
    movie_link = 'https://movie.douban.com/subject/{}/'.format(movie_id)
    search_result = movie_data[movie_data['链接'] == movie_link].iloc[0]
    movie_name = search_result['电影名']
    movie_score = search_result['评分']
    return (movie_name,movie_score)

def generate_wordcloud(word_list,path_name):
    wordcloud = WordCloud()
    wordcloud.add(
        "",
        tuple(zip(keywords_counts.index,keywords_counts)),word_size_range = [20,100])
    wordcloud.render(path_name)
    print(f"Generate word cloud file done: {path_name}")

# 创建列表, 每个列表都含有10个列表
kw_list_by_score=[[] for i in range(10)]
kw_counts_by_score = [[] for i in range(10)]

movie_id_list = get_movie_idList(300)
for movie_id in movie_id_list:
    word_list = get_comment_keywords(movie_id,30)
    movie_name, movie_score = get_movie_name_and_score(movie_id)
    try:
        kw_list_by_score[math.floor(movie_score)].extend(word_list.index)
        kw_counts_by_score[math.floor(movie_score)].extend(word_list.values)
    except:
        print('Something Error!!!')

for i in range(10):
    if kw_list_by_score[i]:
        kw30_with_counts = pd.DataFrame({
            'kw':kw_list_by_score[i],
            'count':kw_counts_by_score[i]
            })
        kw30_with_counts = kw30_with_counts.groupby('kw').sum()
        kw30_with_counts = kw30_with_counts.sort_values(by = 'count', ascending = False)[:30]
        counts_sum = kw30_with_counts['count'].sum()
        kw30_with_counts['percentage'] = kw30_with_counts['count'] / counts_sum
        kw30_with_counts.to_csv('{}_movie_keywords.csv'.format(i))


from pyecharts.charts import HeatMap

kw_counts_by_score=[[] for _ in range(10)]
for i in range(4,10):
	kw_counts_by_score[i] = pd.read_csv('{}_movie_keywords.csv'.format(i))
	kw_percentage_df = pd.DataFrame([],
		columns = list(range(4,10)),
		index=kw_counts_by_score[9]['kw'][:10])

for i in range(4,10):
	kw=kw_counts_by_score[i]
	kw=kw[kw['kw'].isin(kw_percentage_df.index)]
	kw_percentage_df[i] = pd.Series(list(kw['percentage']),index=kw['kw'])

kw_percentage_df.fillna(0,inplace=True)

data=[]
i = 0
for index in kw_percentage_df.index:
	j=0
	for column in kw_percentage_df.columns:
		data.append([j,i,kw_percentage_df[column][index]*100])
		j+=1
	i+=i

heatmap = HeatMap()
heatmap.add_xaxis(list(kw_percentage_df.columns))
heatmap.add_yaxis("电影评论关键词热力图",list(kw_percentage_df.index),data)
heatmap.set_global_opts(
	visualmap_opts=opts.VisualMapOpts(
		min_= 0,
		max_=10,
		orient='horizontal'
		),
	)
heatmap.render(path="heatmap.html")

 

你可能感兴趣的:(数据分析,数据可视化,python)