韩剧荒,于是去爬了下豆瓣~~

第一步,利用selenium爬虫

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from lxml import etree
from tkinter import *
import warnings
warnings.filterwarnings('ignore')
import json
import pandas as pd
import time


option = webdriver.ChromeOptions()
option.add_argument('disable-infobars')
option.add_argument('--headless')  # 隐藏窗口
browser = webdriver.Chrome(chrome_options=option)
browser_detail = webdriver.Chrome(chrome_options=option)
browser.maximize_window()
wait = WebDriverWait(browser, 10)
keyword = '韩剧'
rank = 'recommend'
global click_times
click_times = 5
all_directors = []
all_actors = []
all_stars5_rate = []


def login():
    #页面加载
    login_url = 'https://accounts.douban.com/passport/login'
    browser.get(login_url)
    login_handle = browser.current_window_handle
    # print(login_handle)

    submit = wait.until(
        EC.presence_of_element_located((
            By.CSS_SELECTOR,
            '.account-tab-account'
        ))
    )
    submit.click()

    user_name = wait.until(
        EC.presence_of_element_located((
            By.CSS_SELECTOR,
            '#username')))
    password = wait.until(
        EC.presence_of_element_located((
            By.CSS_SELECTOR,
            '#password'
        ))
    )

    submit = wait.until(
        EC.presence_of_element_located((
            By.CSS_SELECTOR,
            'a.btn:nth-child(1)'
        ))
    )

    #输入登陆账号信息
    user_name.send_keys('#####')
    password.send_keys('#####')

    #模拟登陆
    submit.click()
    return login_handle


def index(login_handle):
    cookies = browser.get_cookies()
    # print(cookies)
    url = 'https://movie.douban.com/tv/#!type=tv&tag=' + keyword + '&sort=' + rank + '&page_limit=20&page_start=0'
    js = 'window.open("{}");'.format(url)
    browser.execute_script(js)
    browser.get(url)
    # index_handle = browser.current_window_handle
    windows = browser.window_handles
    browser.switch_to_window(windows[1])
    browser.close()
    browser.switch_to_window(windows[0])
    time.sleep(3)

    #点击加载更多
    # global click_times
    # click_times = 4
    for i in range(click_times):
        more = wait.until(
            EC.presence_of_element_located((
                By.CSS_SELECTOR,
                '#content > div > div.article > div > div.list-wp > a'
            ))
        )
        browser.execute_script("window.scrollTo(0, document.body.scrollHeight)")
        time.sleep(2)
        more.click()

    html = browser.page_source
    return html


def parse_index(html):
    etree_html = etree.HTML(html)
    names = etree_html.xpath('//div[@class="list-wp"]/div[@class="list"]/a[@class="item"]/div[@class="cover-wp"]/img/@alt')
    scores = etree_html.xpath('//div[@class="list-wp"]/div[@class="list"]/a[@class="item"]/p/strong/text()')
    href = etree_html.xpath('//div[@class="list-wp"]/div[@class="list"]/a[@class="item"]/@href')
    df = pd.DataFrame({'names': names, 'scores': scores})
    df['scores'] = pd.to_numeric(df['scores']) 
    return href, df


def detail(href):
    for i in range(click_times * 20):
        print('正在解析第', str(i+1), '部剧')
        director_list = []
        actor_list = []
        url = href[i]
        if url:
            # js = 'window.open("{}");'.format(url)
            # browser.execute_script(js)
            # windows = browser.window_handles
            browser_detail.get(url)
            html = browser_detail.page_source
            # browser.switch_to_window(windows[0])
            # print(html)
            compile1 = re.compile(r'<script type="application/ld\+json">(.*?)</script>', re.S)
            html0 = re.findall(compile1, html)[0]
            data = json.loads(html0, strict=False)
            # print(data)
            if data and 'director' in data.keys():  # 导演
                # print(data.get('director'))
                for item in data.get('director'):
                    # print(item.get('name'))
                    director_list.append(item.get('name').split()[0])
            # print(director_list)
            all_directors.append(director_list)
            if data and 'actor' in data.keys():  # 演员
                # print(data.get('actor'))
                for item in data.get('actor'):
                    # print(item.get('name'))
                    actor_list.append(item.get('name').split()[0])
            print(actor_list)
            all_actors.append(actor_list)

            etree_html = etree.HTML(html)
            stars5_rate = etree_html.xpath('//div[@class="ratings-on-weight"]//span[@class="rating_per"]/text()')[0]
            all_stars5_rate.append(stars5_rate)
        else:
            all_directors.append([])
            all_actors.append([])
            all_stars5_rate.append([])

    actors_df = pd.DataFrame({'actors': all_actors})
    director_df = pd.DataFrame({'directors': all_directors})
    stars5_df = pd.DataFrame({'star5_rate': all_stars5_rate})
    return actors_df, director_df, stars5_df


def main():
    start_time = time.time()
    login_handle = login()
    html = index(login_handle)
    # print(html)
    href, df = parse_index(html)
    actors_df, director_df, stars5_df = detail(href)
    concat_df = pd.concat([df, stars5_df, actors_df, director_df], axis=1)
    print(concat_df.head(10))
    concat_df.to_csv('douban_scrapy.csv', encoding='utf_8_sig')

    browser.close()
    browser.quit()

    waiste_time = time.time() - start_time
    print('此次爬虫用时:', waiste_time)


if __name__ == '__main__':
    main()

第二步,导入数据开始分析

# 导入相关包
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
import collections
import wordcloud
from PIL import Image
import seaborn as sns
%matplotlib inline
import matplotlib
import re
pd.set_option('display.max_row', 100)
pd.set_option('display.max_colwidth', 100)
# 读取数据,查看数据,修改数据
data = pd.read_csv('./Desktop/douban_scrapy.csv').iloc[:,1:]
data.info()
# 修改数据类型
data['star5_rate'] = data['star5_rate'].apply(lambda x: float(x.replace('%', '')))
# 按五星好评率和评分降序排列
df_sortByScores = data.sort_values(['star5_rate', 'scores'], ascending=False)
df_sortByScores.head()
前100部热门韩剧总体情况
# 前100个样本,平均评分为8.215,平均五星好评率为41.83%,最高评分为9分,最低得分为5分。
df_sortByScores.describe()

韩剧荒,于是去爬了下豆瓣~~

评分情况分析

# 找出最高评分和最低评分的韩剧名称。
print('评分最高的电视剧及其评分:', '\n', 
      '名称:', df_sortByScores[df_sortByScores['scores'] == df_sortByScores['scores'].max()]['names'].tolist()[0],
      '\n',
      '评分:', df_sortByScores['scores'].max(),
      '\n')
print('评分最低的电视剧及其评分:', '\n',
      '名称:', df_sortByScores[df_sortByScores['scores'] == df_sortByScores['scores'].min()]['names'].tolist()[0],
      '\n',
      '评分:', df_sortByScores['scores'].min())

# 打印信息:
评分最高的电视剧及其评分: 
 名称: 请回答1988 
 评分: 9.7 

评分最低的电视剧及其评分: 
 名称: 河伯的新娘2017 
 评分: 5.0
# 评分分布情况,50%的评分在8.3以上。
plt.figure(figsize=(18, 8))
sns.countplot(x='scores', data=df_sortByScores)
plt.tick_params(labelsize=10)
plt.savefig('/Users/mac/Desktop/评分分布.jpg')

韩剧荒,于是去爬了下豆瓣~~

# 评分区间占比
pie_data = df_sortByScores.iloc[:, 0:3]
scores_bins = np.arange(0, 11, 1)
pie_data['scores_cut'] = pd.cut(pie_data['scores'], scores_bins)
pie_data['scores_cut'] = pie_data['scores_cut'].astype('str')
scores_label = pie_data['scores_cut'].value_counts().index.tolist()
scores_counter = pie_data['scores_cut'].value_counts().values.tolist()
plt.figure(figsize=(10,10))
plt.pie(scores_counter, labels=scores_label, autopct='%1.1f%%')
plt.savefig('/Users/mac/Desktop/评分区间占比.jpg')

韩剧荒,于是去爬了下豆瓣~~

# 根据评分透视电视剧,并按评分降序排列
df_sortByScores[['scores', 'names']].pivot_table(index='scores', aggfunc=lambda x: ', '.join(x)).sort_values(['scores'], ascending=False)

韩剧荒,于是去爬了下豆瓣~~韩剧荒,于是去爬了下豆瓣~~

五星好评率情况分析

# 五星好评率大于50的韩剧数量,一共有29部。
star5_rate_count = collections.Counter(df_sortByScores['star5_rate'])
# star5_rate_count
star5_rate_count_df = pd.DataFrame({'star5_rate': list(star5_rate_count.keys()),
                                'star5_rate_count': list(star5_rate_count.values())})
# star5_rate_count_df.info()
star5_rate_moreThan50 = star5_rate_count_df[star5_rate_count_df['star5_rate'] >= 50].shape[0]
print('五星好评率大于50的韩剧数量:', star5_rate_moreThan50)

# 打印信息:
五星好评率大于50的韩剧数据: 29
star5_rate_bins = np.arange(0, 100, 10)
pie_data['star5_rate_cut'] = pd.cut(pie_data['star5_rate'], star5_rate_bins)
pie_data['star5_rate_cut'] = pie_data['star5_rate_cut'].astype('str')
star5_rate_label = pie_data['star5_rate_cut'].value_counts().index.tolist()
star5_rate_counter = pie_data['star5_rate_cut'].value_counts().values.tolist()
plt.figure(figsize=(10,10))
plt.pie(star5_rate_counter, labels=star5_rate_label, autopct='%1.1f%%')
plt.savefig('/Users/mac/Desktop/五星好评率分布.jpg')

韩剧荒,于是去爬了下豆瓣~~

# 五分好评率前十的韩剧,有时候评分不太靠谱,五分好评率是个不错的参考指标。
df_sortByScores[['star5_rate', 'names']].sort_values(['star5_rate'], ascending=False)[:10]

韩剧荒,于是去爬了下豆瓣~~

演员情况分析

# 拿出前100部韩剧出演的演员。
actors_list = []
for item in df_sortByScores['actors']:
    item = item.replace('[', '').replace(']', '').replace('\'', '').replace('\'', '').split(',')
    actors_list.extend(item)
# print(actors_list)

# 统计演员参演次数。
actors_word_counts = collections.Counter(actors_list)
actors_count_df = pd.DataFrame({'actors_names': list(actors_word_counts.keys()),
                          'actors_times': list(actors_word_counts.values())})
# 筛选出参演次数大于等于5的演员,发现前面的大都是老戏骨,现在比较热门稍微往后靠。
actors_df_bigger_than_5 = actors_count_df[actors_count_df['actors_times'] >= 5].sort_values(['actors_times'], ascending=False)
actors_df_bigger_than_5

# 打印信息:
	actors_names	actors_times
190	金元海	11
192	李俊赫	9
33	孙荣顺	9
420	金美京	9
225	严孝燮	9
134	成东日	8
352	利旻	8
49	刘在明	8
730	吴义植	7
345	李彩京	7
284	全振序	7
118	李圭燮	7
235	朴健洛	7
228	崔镇浩	7
585	金光奎	7
221	崔秉默	7
372	赵在允	6
226	尹敬浩	6
216	李成俊	6
726	李钟硕	6
5	金善映	6
186	孙钟学	6
651	安内相	6
180	尹仲勋	6
571	徐光载	6
165	丁文晟	6
741	南基爱	6
752	罗映姫	5
398	尹柱万	5
353	金旻奎	5
659	刘仁娜	5
378	金炳哲	5
380	金惠恩	5
388	金智媛	5
838	姜其永	5
765	南柱赫	5
405	申秀妍	5
614	丹尼尔·乔伊·奥尔布赖特	5
514	吴雅琳	5
551	徐正妍	5
484	朴元尚	5
492	郑栋焕	5
496	张文硕	5
513	高圭弼	5
485	李伊庚	5
250	张铉诚	5
340	李宥俊	5
313	南多凛	5
39	丁海寅	5
47	李振权	5
50	禹贤	5
76	李光洙	5
81	金學善	5
95	高甫洁	5
105	全国焕	5
115	黃相庆	5
126	郑秀晶	5
147	张赫镇	5
175	姜河那	5
179	李璟荣	5
188	吴闵硕	5
194	金正洙	5
201	丁世亨	5
202	孟奉鶴	5
208	崔英	5
214	黄锡晶	5
234	张成范	5
240	李豪宰	5
242	权赫洙	5
251	李时言	5
261	南文哲	5
288	金姬贞	5
292	金贤彬	5
939	李必模	5

重点来啦!!!

# 看下我二硕和朴宝拉的出现情况,二硕严重推荐《听见你的声音》和《当你沉睡时》,朴宝英严重推荐《噢我的鬼神大人》和《大力女都丰顺》。
print('前100韩剧中李钟硕出现次数:', actors_word_counts.get('李钟硕'))
print('前100韩剧中朴宝英出现次数:', actors_word_counts.get('朴宝英'))

# 打印信息:
前100韩剧中李钟硕出现次数: 6
前100韩剧中朴宝英出现次数: 2
# 李钟硕出演的韩剧。
df_sortByScores[df_sortByScores.actors.str.contains('李钟硕')][['names', 'scores']].sort_values(['scores'], ascending=False)

韩剧荒,于是去爬了下豆瓣~~

# 朴宝英出演的韩剧。
df_sortByScores[df_sortByScores.actors.str.contains('朴宝英')][['names', 'scores']].sort_values(['scores'], ascending=False)

韩剧荒,于是去爬了下豆瓣~~

最后看看导演

# 拿出前100部韩剧的导演。
directors_list = []
for item in df_sortByScores['directors']:
    item = item.replace('[', '').replace(']', '').replace('\'', '').replace('\'', '').split(',')
    directors_list.extend(item)
# print(directors_list)

directors_word_counts = collections.Counter(directors_list)
director_df = pd.DataFrame({'directors_names': list(directors_word_counts.keys()),
                            'directors_scores': list(directors_word_counts.values())})
# 无导演的是动画片,可忽略。
director_df.sort_values(['directors_scores'], ascending=False)

# 打印信息:
	directors_names	directors_scores
9		8
0	申源浩	4
10	李应福	4
14	金炳洙	4
50	朴信宇	3
1	金秉旭	3
5	金元锡	3
35	朴俊和	3
7	金奎泰	3
33	陈赫	3
15	李政孝	2
40	宋贤旭	2
57	金洪善	2
59	全基尚	2
19	安畔锡	2
22	李亨民	2
13	李胜英	2
3	金昌东	2
4	洪忠灿	2
12	金英基	2
6	安吉镐	2
67	朴洪均	1
54	尹成植	1
47	朴秀真	1
48	申承佑	1
70	姜信孝	1
49	池英洙	1
51	柳济元	1
52	李炳勋	1
69	朱东民	1
53	郑大允	1
55	金道勋	1
66	咸俊浩	1
56	李明佑	1
68	金成旭	1
58	李容硕	1
60	洪成昌	1
61	毛完日	1
62	表民洙	1
45	金政民	1
63	尹成浩	1
64	表民洙	1
65	崔成范	1
46	吴庆焕	1
36	金尹哲	1
44	张正道	1
26	金镇元	1
2	李英哲	1
8	申景秀	1
11	河炳勋	1
16	金镇满	1
17	金大镇	1
18	崔哉玧	1
20	赵贤卓	1
21	李太坤	1
23	刘仁值	1
24	李昌民	1
25	朴秀真	1
27	崔正奎	1
43	金希元	1
28	金锡允	1
29	赵秀沅	1
30	申承佑	1
31	李政燮	1
32	金振宇	1
34	吴贤钟	1
37	张太维	1
38	申宇哲	1
39	金尚昊	1
41	权锡章	1
42	李娜静	1
71	富圣哲	1

没错,这篇其实根本不是什么技术分析文章,只是一篇二硕和朴宝英脑残粉的软文。