数据可视化案例

数据可视化案例

使用豆瓣电影中的数据来进行可视化,网址:豆瓣电影 Top 250 (douban.com)

一、网页数据分析

在这里插入图片描述

我们需要爬取的是豆瓣电影Top250网页每一页电影名称图片链接导演年份国家电影类型电影评分这些数据。

在待爬取的网页中,按下F12键进入开发者模式,这样可以让我们很方便的找到网页中每一块数据对应的源码。

在这里插入图片描述

通过以上方式可以让我们很快的找到图片对应的标签,通过观察,我们可以找到每一个图片的链接都存放在<img>标签的src属性下。

同样的,我们可以找到电影名称所在的标签。
请添加图片描述

可以知道电影名称所在的位置是<span>标签的值。

在这里插入图片描述

我们可以发现导演、年份、国家类型都在<p>标签下,这种情况我们就需要后期的处理了,先简单的得到<p>标签的数据,然后再通过字符串的分割、选取、剔除等操作可以得到最终我们需要的数据。
在这里插入图片描述

最后一个是评分标签,我们通过同样的方式可以找到评分在<span class="rating_num">标签中,并且是<span class="rating_num">标签的值。

由于我们需要的是每一页的标签,一个简单的可行的思路是找到后页标签对应的标签,这里找到的是<a>标签,<a>标签属性href的值对应的是下一页的网址,如果<a>标签的属性为空时,说明没有下一页了,可以停止爬取了。
在这里插入图片描述

通过以上分析,我们开始编写爬虫程序来爬取数据,这里我们使用scrapy爬虫框架来进行爬取数据。

二、数据爬取(获取数据)

1. 安装scrapy

pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple

2. 初始化scrapy项目

scrapy startproject Douban

在这里插入图片描述

使用PyCharm打开项目,可以观察到项目的整体结构如下:

在这里插入图片描述

3. 设置数据结构

items.py文件

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class DoubanItem(scrapy.Item):
    imgUrl = scrapy.Field()  # 图片链接
    name = scrapy.Field()   # 电影名称
    author = scrapy.Field()  # 导演名称
    year = scrapy.Field()   # 年份
    country = scrapy.Field()  # 国家
    types = scrapy.Field()   # 电影类型
    score = scrapy.Field()   # 电影评分

4. 创建爬虫程序

scrapy genspider douban "movie.douban.com"   # douban是爬虫的名称, "movie.douban.com"是要爬取网址的域名

在这里插入图片描述

在这里插入图片描述

打开爬虫文件,更改带爬取的文件的网址:

在这里插入图片描述

编写爬虫程序douban.py
import scrapy
from ..items import DoubanItem

class DoubanSpider(scrapy.Spider):
    name = "douban"
    allowed_domains = ["movie.douban.com"]
    start_urls = ["https://movie.douban.com/top250"]

    def parse(self, response):
        doubans = response.xpath("//ol[@class='grid_view']/li")
        for douban in doubans:
            item = DoubanItem()
            item['name'] = douban.xpath("div[@class='item']/div[2]/div[1]/a/span/text()").extract_first()
            item['imgUrl'] = douban.xpath("div/div[@class='pic']/a/@href").extract_first()
            text = douban.xpath("div/div[@class='info']/div[@class='bd']/p/text()").extract()[1]
            fs_text = douban.xpath("div/div[@class='info']/div[@class='bd']/p/text()").extract()[0]
            item['author'] = fs_text.split(" ")[0].strip().split(" ")[1: -1]
            item['score'] = douban.xpath(
                "div/div[@class='info']/div[2]/div[@class='star']/span[2]/text()").extract_first()
            c_start = text.find("/")
            c_end = text.find("/", c_start + 1)
            country = text[c_start + 1: c_end]
            year = text[: c_start]
            types = text[c_end:]

            country_analyse = country.split(" ")
            country_have = country_analyse[1].split(" ") if len(country_analyse) > 1 else country_analyse[0].split(" ")
            item['country'] = country_have if country_have != [""] else ["中国大陆"]
            item['year'] = year.split(" ")[0].strip()
            item['types'] = types.split(" ")[1].strip().split(" ")

            yield item

            next_page = response.xpath("/html/body/div[3]/div[1]/div[1]/div[1]/div[2]/span[3]/a/@href").extract_first()
            if next_page:
                yield response.follow(next_page, self.parse)

配置settings.py文件:
  1. 首先设置代理USER_AGENT
# 第17行
USER_AGENT  = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
  1. 设置不服从ROBOOTS协议:
ROBOTSTXT_OBEY = False    # 第20行

5. 运行爬虫程序

scrapy crawl douban -o ./Data/douban.json 

在这里插入图片描述

在这里插入图片描述

打开douban.json数据可以查看到爬取到的结果:

在这里插入图片描述

三、数据处理与可视化

数据处理部分,我们使用Pandas库来对数据进行处理,可视化部分,我们使用pyecharts库来进行数据可视化。

pyecharts参考网站:pyecharts

创建目录结构:
在这里插入图片描述

数据处理:

编写DataAnalyze.py文件
import json
import pandas as pd

path = '../Data/douban.json'
with open(path, 'r', encoding='utf-8') as file:
    global data
    data = json.load(file)



def YearNumTop_5() -> tuple:
    '''
    :return: 发布电影次数最多的前五名年份以及电影次数
    '''
    years = []
    for movie in data:
        years.append(movie['year'][:4])

    # 统计数据出现的次数
    y = pd.Series(years)
    y_count = y.value_counts()   # value_counts函数会统计次数并且进行自动的排序,降序
    y_count = y_count.head(5)
    # print(y_count)
    x_list = y_count.index.tolist()   # 将索引转换为列表
    y_list = y_count.values.tolist()   # 将值转换为列表
    # print(x_list, y_list)
    return (x_list, y_list)


def TpyeNum() -> tuple:
    '''
    :return: 电影类型及类型出现的次数
    '''
    types = []
    for type in data:
        types.extend(type['types'])
    # print(types)
    tp = pd.Series(types)
    tp = tp.value_counts()[1: -2]
    tp_label = tp.index.tolist()  # tolist用于将pandas中的Series或DataFrame转换为列表对象
    tp_count = tp.values.tolist()
    # print(tp_label, tp_count)
    return (tp_label, tp_count)


def YearMovies() -> tuple:
    '''
    :return: 年份,以及每一年的电影
    '''
    name = []
    year = []
    tree_dict = {}
    for movie in data:
        name.append(movie["name"])
        year.append(movie['year'])
    for n, y in zip(name, year):
        # print(z)
        # print(n, y)
        if tree_dict.get(y) is None:
            tree_dict[y] = [n]  # 如果键不存在,初始化为列表
        else:
            tree_dict[y].append(n)

    # 我们只取得前5年的数据
    keys_sliced = list(tree_dict.keys())[0: 5]
    tree_part = {key: tree_dict[key] for key in keys_sliced}
    # print(keys_sliced, tree_part)
    return (keys_sliced, tree_part)


def CountryNum() -> tuple:
    '''
    :return: 返回国家以及每个国家的电影数量
    '''
    country = []
    for movie in data:
        country.extend(movie['country'])
    # print(country)
    cou = pd.Series(country)
    cou_sort = cou.value_counts()
    country_ans = cou_sort.index.tolist()
    count_ans = cou_sort.values.tolist()
    # print(country_ans, count_ans)
    return (country_ans, count_ans)


if __name__ == '__main__':
    CountryNum()

可视化:

1. 锥形图
from pyecharts import options as opts
from pyecharts.charts import Funnel
from DataAnalyze import YearNumTop_5

data = YearNumTop_5()

funnel_table = (
    Funnel()
    .add("年份-电影数量", [list(z) for z in zip(data[0], data[1])])
    .set_global_opts(title_opts=opts.TitleOpts(title="Top-5"))
    .render("../SourceChart/Funnel.html")
)

在这里插入图片描述

2. 词云图
from pyecharts import options as opts
from pyecharts.charts import WordCloud
from pyecharts.globals import SymbolType
from DataAnalyze import TypeNum

label, count = TypeNum()
words = [(l, c) for l, c in zip(label, count)]   # 使用列表生成式,生成元素为元组的列表

wordCloud = (
    WordCloud()
    .add("电影类型", words, word_size_range=[20, 100], shape=SymbolType.DIAMOND)
    .set_global_opts(title_opts=opts.TitleOpts(title="Movie Type Distribution"))
    .render("../SourceChart/WordCloud.html")
)

在这里插入图片描述

3. 雷达图
from pyecharts import options as opts
from pyecharts.charts import Radar
from DataAnalyze import TypeNum

types = TypeNum()

data = [{"value": types[1], "name": "电影类型"}]
# 设置雷达图的取值范围,最大为57,最小为0
max = 57
min = 0

c_schema = [
    {"name": name, "max": max, "min": min} for name in types[0]
]

radar = (
    Radar()
    .set_colors(["#4587E7"])
    .add_schema(
        schema=c_schema,
        shape="circle",
        center=["50%", "50%"],
        radius="80%",
        angleaxis_opts=opts.AngleAxisOpts(
            min_=0,
            max_=360,
            is_clockwise=False,
            interval=5,
            axistick_opts=opts.AxisTickOpts(is_show=False),
            axislabel_opts=opts.LabelOpts(is_show=False),
            axisline_opts=opts.AxisLineOpts(is_show=False),
            splitline_opts=opts.SplitLineOpts(is_show=False),
        ),
        radiusaxis_opts=opts.RadiusAxisOpts(
            min_=min,
            max_=max,
            interval=2,
            splitarea_opts=opts.SplitAreaOpts(
                is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
            ),
        ),
        polar_opts=opts.PolarOpts(),
        splitarea_opt=opts.SplitAreaOpts(is_show=False),
        splitline_opt=opts.SplitLineOpts(is_show=False),
    )
    .add(
        series_name="电影分类",
        data=data,
        areastyle_opts=opts.AreaStyleOpts(opacity=0.1),
        linestyle_opts=opts.LineStyleOpts(width=1),
    )
    .render("../SourceChart/Radar.html")
)

在这里插入图片描述

4. 树图
import pyecharts.options as opts
from pyecharts.charts import Tree
from DataAnalyze import YearMovies


year, movie_data = YearMovies()

# 构造类似于递归字典的数据类型
for y in year:
    movie_data[y] = [{"name": value, "children": 1} for value in movie_data[y]]
data = [{'name': y, 'children': movie_data[y]} for y in year]
data = {'name': "电影", 'children': data}

tree = (
    Tree()
    .add(
        series_name="",
        data=[data],
        pos_top="18%",
        pos_bottom="14%",
        layout="radial",
        symbol="emptyCircle",
        symbol_size=7,
    )
    .set_global_opts(
        tooltip_opts=opts.TooltipOpts(trigger="item", trigger_on="mousemove")
    )
    .render("../SourceChart/Tree.html")
)

在这里插入图片描述

5. 地图
from pyecharts import options as opts
from pyecharts.charts import Map
from DataAnalyze import CountryNum
from translate import Translator

# 实例话翻译类:从中文翻译为英文
translator = Translator(from_lang="Chinese", to_lang="English")
data = CountryNum()
# 对每一个数据进行翻译
for idx, cou in enumerate(data[0]):
    if cou == "美国":
        data[0][idx] = "United States"
        continue
    if cou == "英国":
        data[0][idx] = "United Kingdom"
        continue
    if cou in ["中国大陆", "中国香港", "中国台湾", "1964(中国大陆)"]:
        cou = "中国"
    target = translator.translate(f'{cou}')
    data[0][idx] = target
    if idx % 5 == 0:
        print(target)


map_table = (
    Map()
    .add("上映地区", [list(z) for z in zip(data[0], data[1])], "world")
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        title_opts=opts.TitleOpts(title="Map-世界地图"),
        visualmap_opts=opts.VisualMapOpts(max_=145),
    )
    .render("../SourceChart/Map.html")
)

在这里插入图片描述

5. 将所有图汇总到一张网页上

如果要把所有图表汇总到一个网页上,那么需要将每一个绘制图的./render给注释掉,类似与下面这样,否则会将图表识别为字符串类型的数据。

在这里插入图片描述

Summary.py

from pyecharts.charts import Page
from Funnel import funnel_table
from Map import map_table
from Radar import radar
from Tree import tree
from WordCloud import wordCloud


# 初始化网页
page = Page(layout=Page.DraggablePageLayout)
page.add(map_table)  # 添加地图
page.add(radar)      # 添加雷达图
page.add(tree)      # 添加树图
page.add(wordCloud)  # 添加词云图
page.add(funnel_table)     # 添加漏斗图
page.render("../SourceChart/Summary.html")

在这里插入图片描述

声明:本项目只用于学习,禁止用于任何非法的行为。—— 2024.6.16

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/715408.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

17岁中专女生,闯进全球数学竞赛12强

今年阿里的数学竞赛结果出来了&#xff0c;在榜单的前列包含一个 17 岁的中专女生。 在 2018 年时&#xff0c;阿里巴巴达摩院发起了一个国际数学竞赛&#xff0c;基本每年举办一次&#xff0c;参赛不设报名条件&#xff0c;向全球所有数学爱好者开放&#xff0c;竞赛由阿里创…

AOSP平台开发的利器——Android Studio for Platform

Android Studio for Platform (ASfP) 是一个为使用 Soong 构建系统构建的 Android 开源项目&#xff08;AOSP&#xff09;平台开发者而设计的 Android Studio IDE 版本。与标准 Android Studio 不同&#xff0c;ASfP 具有多语言支持&#xff0c;可以在同一 IDE 中编写 C、Kotli…

java高级——Arrays工具类(包含核心的归并和二分排序以及多个底层知识点)

java高级——Arrays工具类 前情提要文章介绍提前了解的知识点1 二分查找思想 Arrays常用方法介绍&#xff08;8大类&#xff09;1. 创建数组1.1 copyOf&#xff08;&#xff09;1.2 copyOfRange&#xff08;&#xff09;1.3 fill&#xff08;&#xff09; 2. 数组转集合&#x…

数据库-数据定义和操纵-初始MySQL数据库

连接数据库&#xff1a; mysql -u用户名 -p密码 创建数据库&#xff1a; create database 数据库名; 命令查看MySQL中已存在的数据库 show database; 数据库中创建表的规则&#xff1a; CREATE TABLE 表名 (字段名,数据类型,字段名,数据类型,..... ) eg: 首先创建数据库&am…

操作系统—页表(实验)

文章目录 页表1.实验目标2.实验过程记录(1).增加打印页表函数(2).独立内核页表(3).简化软件模拟地址翻译 3.实验问题及相应解答问题1问题2问题3问题4 实验小结 页表 1.实验目标 了解xv6内核当中页表的实现原理&#xff0c;修改页表&#xff0c;使内核更方便地进行用户虚拟地址…

youlai-boot项目的学习—工程构建与运行

开发环境 系统:mac OS Ventura 13.2.1 终端: item2 Homebrew: 4.3.5 IDE: IntelliJ IDEA 2024.1.1 (Ultimate Edition) 代码分支 仓库&#xff1a;https://gitee.com/youlaiorg/youlai-boot.git 分支&#xff1a; master commit: 9a753a2e94985ed4cbbf214156ca035082e02723 …

python数据分析---ch11 python数据描述性统计

python数据分析--- ch11 python数据描述性统计 1. Ch11--描述性统计2. 数据集中趋势的度量2.1 平均值2.2 中位数2.3 众数2.4 几何平均值2.5 调和平均值 3. 数据离散趋势的度量3.1 极差3.2 平均绝对偏差(MAD)3.3 方差和标准差3.4 下偏方差和下偏标准差3.5 目标下偏方差和目标下偏…

【Qt项目专栏】贪吃蛇小游戏1.0

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 贪吃蛇小游戏1.0 项目编号&#xff1a;01 文章目录 贪吃蛇小游戏1.0一…

生信技能48 - 如何获取基因的SNP及RefSeq参考序列命名规则

1. SNP概念 SNP 是指基因组水平上由单个核苷酸的变异所引起的DNA 序列多态性,在群体中的发生频率不小于1 %,包括单个碱基的转换、颠换、插入和缺失等。每核苷酸发生突变的概率大约为10 -9 , 由于压力选择,SNP在单个基因和基因组以及动物不同种群间分布是不均匀的,在非编码…

虚拟机使用桥接模式网络配置

1、获取本机的网络详细信息 windowr 输入cmd 使用ipconfig -all 一样即可 在自己的虚拟机中设置网络 虚拟机中的ip ---------192.168.36.*&#xff0c;不要跟自己的本机ip冲突 网关-----------192.168.36.254 一样即可 dns -----------一样即可&#xff0c;我多写了几个&am…

C | 在ubuntu22下开发的一些配置

目录 VScode设置 要下载的插件&#xff1a; 卸载VScode的话就是哪装的哪删。 浅用gcc 预处理指令 使用gcc 语言编译过程 1. 预处理&#xff08;Preprocessing&#xff09; 2. 编译&#xff08;Compilation&#xff09; 3. 汇编&#xff08;Assembly&#xff09; 4. …

最长回文子串问题详解

最长回文子串的问题描述&#xff1a;给出一个字符串S&#xff0c;求S的最长回文子串的长度。 针对这个问题&#xff0c;先看暴力解法&#xff1a;枚举子串的两个端点i和j&#xff0c;判断在[i,j]区间内的子串是否回文。从复杂度上来看&#xff0c;枚举端点需要&#xff0c;判断…

Linux、Windows安全加固

为了减少系统被黑客入侵&#xff0c;对操作系统的安全加固是网络安全和主机安全必不可少的一部分。 一、Linux安全加固 1.不使用默认的ssh端口&#xff0c;修改默认ssh22端口号 sudo vim /etc/ssh/ssh_config 去掉#注释&#xff0c;修改端口号并保存 2.关闭不必要的系统服务…

芯片验证分享8 —— 代码审查2

大家好&#xff0c;我是谷公子&#xff0c;上节课给大家讲了代码审查中的代码正向检查&#xff0c;今天我们来讲代码审查的其他方法。 今天介绍的检查方法有&#xff1a; 代码反向检查 桌面检查 同行评审 可用性验证 这些验证方法可以应用在芯片开发的任何阶段。代码审查…

vitepress搭建的博客系统cdn引入github discussions评论系统

github仓库必须是公开的。 按照CDN的方式引入 打开discussions模块 安装giscus app 配置giscus 就是刚安装了giscus app的仓库 页面往下走&#xff0c;生成了代码&#xff1a; 配置vitepress 采用了CDN的方式引入 使用web component 随便找个地方试试组件 效果 有了…

Windows 托盘图标实现类封装及使用(附源码)

在系统桌面右下角的托盘区域,创建一个托盘图标,已经是很多软件的标配了,特别是IM即时通讯软件,要在托盘图标上显示来消息时的闪动头像。 其实托盘图标创建很简单,使用起来也比较方便,主要是调用Shell_NotifyIcon API函数,传入不同参数表示对应的操作: 1)NIM_AD…

ROS创建一个软件包

 首先&#xff0c; 配置您的 ROS 2 安装环境。 让我们使用您在 先前教程 中创建的工作空间 ros2_ws 来创建您的新软件包。 在运行软件包创建命令之前&#xff0c;请确保您位于 src 文件夹中。 LinuxmacOSWindows cd ~/ros2_ws/src在ROS 2中创建新包的命令语法如下&#…

R进阶使用技巧

Introduction 分享一些R进阶使用的技巧&#xff0c;相当于是之前写的R语言学习的实践和总结了。 Online slide: https://asa-blog.netlify.app/R_tips_for_advanced_use_byAsa/R_tips.html 下载slide和相关的各种test文件: https://asa-blog.netlify.app/R_tips_for_advanced…

会声会影2024一共新增了8项功能

会声会影2024一共新增了8项功能。 一、语音转文字视频中语音能自动转换成文本&#xff0c;节省手动创建字幕时间&#xff01;会声会影2022可以捕获视频中的字幕&#xff0c;并将它应用到任何地方。这个功能是我觉得本次更新中最强大的&#xff0c;再也不需要为手动输入字幕发愁…

以太网基础知识(二)—NRZ,PAM4调制技术

1&#xff1a;码元 了解调制技术需要引出“码元”的概念。 一个码元就是一个脉冲信号&#xff0c;即一个最小信号周期内的信号&#xff0c;我们都能够理解&#xff0c;最简单的电路&#xff0c;以高电平代表1&#xff0c;低电平代表0&#xff0c;一个代表1或者0的信号&#x…