当前位置: 首页 > article >正文

【Project】CupFox电影网站数据爬取分析与可视化

数据采集清洗与数据存储流程如下图所示。

数据分析与数据可视化流程设计如下

1.使用pymongo从数据库中查询所需的数据。对数据进行处理和分析,进行统计、分类、聚合等操作,提取关键指标和洞察。分析结果可以通过编写Python代码进一步优化、筛选和整理,以便于后续可视化展示。

2.使用pyecharts库生成图表对象(如柱状图、折线图、饼图等),将分析结果可视化。通过render_embed()方法将生成的图表嵌入到HTML模板中。使用Flask框架将图表渲染并传输到前端,展示给用户。用户可以在Web界面上交互式地查看图表,了解数据的动态变化和趋势。

数据分析与数据可视化流程如下图所示。

自动化流程设计

代码管理与版本控制

Gitea:作为代码托管平台,团队通过Gitea进行源代码的管理和版本控制。所有代码变更(如新功能开发、Bug修复)都通过Git提交,并同步到Gitea仓库中。

分支管理:采用Git的分支策略,开发人员在不同的分支上进行开发工作(如feature、bugfix、release等),确保主分支(main)保持稳定,避免开发中断。

持续集成

Jenkins:使用Jenkins实现持续集成,自动化构建和测试代码。当代码提交到Gitea仓库后,Jenkins会检测到变更并自动启动构建流程。

Jenkinsfile:通过编写Jenkinsfile脚本定义CI/CD流水线,确保每次提交代码时都进行构建、编译、单元测试等任务,确保代码质量。

容器化与自动化构建

Docker:项目采用Docker容器化技术,将应用及其所有依赖项打包成容器镜像,确保应用在任何环境下都能一致运行。

Dockerfile:使用Dockerfile定义容器镜像的构建过程,包括操作系统、运行时环境、依赖包等的配置。

自动化构建:Jenkins自动触发Docker镜像构建过程,每次代码提交后,自动创建新的容器镜像,并将其推送到镜像仓库。

自动化流程图下图所示。

总体流程

整个项目流程覆盖了从数据采集、存储、分析、展示到自动化部署和安全保障的各个方面,确保了系统的高效性、可扩展性和安全性。

总体流程如下图所示。

图表设计

系统从以下几个方面进行设计与实现:

  1. 电影更新频率分析

图表类型:折线图

用途:折线图适合展示随时间变化的电影更新频率,尤其是月度更新频率的变化趋势。通过折线图,平台可以清晰地看到电影更新的波动情况,并分析哪些时间段更新较为频繁。

  1. 电影产地热度分析

图表类型:地图

用途:地图适用于展示电影产地的热度分布。通过将不同产地的电影数量和观看量等指标映射到地图上,可以直观地看到各个地区的电影资源热度。

  1. 用户评论关键词提取分析

图表类型:词云图

用途:词云图通过可视化用户评论中的高频关键词,能够帮助发现用户的偏好和需求。关键词出现频率越高,字形越大,能够直观显示哪些主题在评论中讨论得最多。

  1. 导演热度分析

图表类型:柱状图

用途:柱状图适合展示不同导演的影片数量和受欢迎程度,能够帮助平台了解哪些导演的作品更受欢迎。

  1. 影片类型占比分析

图表类型:饼图

用途:饼图适合展示平台中各类型电影的资源占比,能够清晰地展示各类型电影在平台中的分布。

项目优势

本项目采用Python3.8编写,具备以下几个主要优势:

Flask Web可视化页面

本项目使用Flask框架开发的Web可视化页面,相较于传统的静态HTML页面,Flask提供了更强的动态交互能力和灵活性。Flask支持模板渲染、路由管理及RESTful接口,使得前后端分离和数据交互更加便捷高效。

Docker容器技术

使用Docker容器技术部署项目,避免了繁琐的环境配置操作,显著简化了项目迁移和部署的复杂度。Docker容器提供了一种轻量级的虚拟化方式,可以确保应用在不同环境中具有一致的运行效果。此外,容器与宿主机之间实现隔离,提升了服务器的安全性和稳定性,减少了环境配置对生产环境的影响。

MongoDB复制集机制

本项目使用了MongoDB的复制集机制,构建了MongoDB集群,支持读写分离和故障转移。主节点负责写入操作,而从节点用于读取,确保系统在高负载情况下的稳定性和响应速度。复制集机制不仅提升了系统的可用性,还增强了数据的安全性,通过数据备份机制防止数据丢失和服务器故障对业务的影响。

DevOps自动化流程

集成Jenkins与Gitea实现了DevOps流程,能够自动化管理代码的构建、测试和部署。结合Docker容器化技术,通过编写Jenkinsfile流水线脚本,将代码打包为Docker容器镜像,支持自动化部署。此流程确保了团队开发的高效协作,同时在多平台(如Kubernetes)上均可运行,大大提升了开发部署和版本更新的效率。

Linux服务器部署与Nginx反向代理

项目部署在Linux服务器上,采用Nginx进行反向代理Flask应用。Nginx不仅能够高效处理大量并发请求,还通过负载均衡和反向代理提高了系统的可扩展性。同时,Nginx还提供了额外的安全性保障,如SSL加密和请求过滤,确保应用的安全性和稳定运行。

工具版本

使用的工具与工具版本如下表x所示。

描述工具版本
解释器Python3.8
Python库Flask3.0.3
Python库jieba0.42.1
Python库pandas2.0.3
Python库pyecharts2.0.6
Python库beautifulsoup44.12.3
Python库pymongo4.10.1
Python库Requests2.32.3
容器运行时Docker-ce27.0.3
数据库 (主从架构)mongodb7.0.12
CI/CD平台jenkins2.462.3
代码仓库gitea22.3.1
操作系统Rocky Linux9.4
web服务器nginx1.25

系统实现

数据采集数据清洗实现

获取所有电影详情页url的关键代码

网站带有请求速度检测反爬,带上请求头,使用time.sleep(random.randint(1, 5)),随机模拟人类访问时间,防止网站拉黑IP。

通过url_get(self,begin_page=1,end_page=3)方法,保存所有的url数据到data_type列表中,返回给video_data_get()方法。

get_url()方法关键代码如下:

for i in range(begin_page, end_page):
    index = i  # 页面数
    url = self.headurl + f"/cupfoxshow/dianying--------{index}---.html"
    
    try:
        data = requests.get(url, headers=self.headers)
        soup = BeautifulSoup(data.text, 'html.parser')
        # 查找所有的 a 标签每页30个url
        elements = soup.find_all('a')
        # 输出每个元素的 href 属性
        for element in elements:
            href = element.get('href')
            if href and '/cupfox/' in href: 
                self.url_path.append(self.headurl + href) -
        print(f"page {i} url add to list succeed")
        time.sleep(random.randint(1, 5))
        
    except Exception as e:
        print("出现异常:", e)

return self.url_path
电影信息数据清洗

requests爬取到网页信息后使用bs4库解析网页,提取需要的数据存入到字典中。

video_data_get()方法关键代码如下:

'''电影信息提取'''
element_info = soup.select(
    'body > div.details > div.container.flex > div.mobile-main.mobile-main-type > div.movie.bj.br.card.border-shadow > div.cf.b-t')

tree2 = element_info[0]

movie_info['名称'] = tree2.find('h1').get_text()
movie_info['图片'] = tree2.find('img').get("src")
movie_info['别名'] = tree2.find('p', class_='cr3').get_text(strip=True).replace("别名:", '').split(",")
movie_info['标签'] = [a.get_text() for a in
                    tree2.select('.scroll-content')[0].find_all('a', target="_blank")]
movie_info['连载'] = tree2.find('p', class_='cr3').find_next('p').get_text(strip=True).replace("连载:", "")
movie_info['导演'] = [a.get_text() for a in
                    tree2.find('p', class_='cr3').find_next('p').find_next('p').find_all("a",target="_blank")]
movie_info['演员'] = [a.get_text() for a in tree2.find_all('p', class_='cr3 starLink')[0].find_all('a')]
movie_info['类型'] = [a.get_text() for a in
                    tree2.find('p', class_='cr3 starLink').find_next("p").find_all('a')]
movie_info['分类'] = tree2.find('p', class_='cr3 starLink').find_next("p").find_next("p").get_text(
    strip=True).replace("分类:", "")
movie_info['更新时间'] = tree2.find('p', class_='cr3 starLink').find_next("p").find_next("p").find_next(
    "p").get_text(strip=True).replace("更新时间:", "")

# 单独提取出影片描述
miaoshu = soup.select(
    "body > div.details > div.container.flex > div.mobile-main.mobile-main-type > div.movie.bj.br.card.border-shadow > div.summary.detailsTxt")
b_cleaned = re.sub(r'\s+', ' ', miaoshu[0].get_text(strip=True))
movie_info['影片描述'] = b_cleaned.replace('展开', '')



'''网友评论提取'''
element = soup.select(
    'body > div.details > div.container.flex > div.mobile-main.mobile-main-type > div:nth-child(6) > ul')
tree1 = element[0]

b_tags = tree1.find_all('b')
p_tags = tree1.find_all('p')

数据存储实现

编写sava_db()类实现数据存储模块,通过传入dict列表,一次性插入多条数据到mongodb中。

其中构造函数通过os库中的getenv方法获取系统中的环境变量修改默认值,能更好的在Linux(容器)中读取环境变量值,而不用修改对应代码来连接mongodb数据库,sava_db()关键代码如下:

class sava_db():
    def __init__(self):
        # 从环境变量中读取配置信息,若未设置则使用默认值
        self.username = os.getenv("MONGO_USERNAME", "root")  # 默认用户名为 root
        self.password = os.getenv("MONGO_PASSWORD", "password123")  # 默认密码为 password123
        self.host = os.getenv("MONGO_HOST", "192.168.100.120")  # 默认主机为 192.168.100.120
        self.port = int(os.getenv("MONGO_PORT", 27017))  # 默认端口为 27017
        self.db = os.getenv("MONGO_DB", "cup_fox_movie")  # 默认数据库为 cup_fox_movie
        self.table = os.getenv("MONGO_TABLE", "movie_data")  # 默认表为 movie_data

    def save_more_data(self, json_list):
        json_list_data = json_list
        myclient = MongoClient(f'mongodb://{self.username}:{self.password}@{self.host}:{self.port}/')
        mydb = myclient[self.db]  # 选中或者创建库
        mycol = mydb[self.table]  # 选中或者创建表
        mydict = json_list_data
        controller_more = mycol.insert_many(mydict)  # 一次插入多条数据
        
        return controller_more

数据分析实现

影片地区与发布年份数据查询

从数据库中查询标签列的所有数据(其中标签列中的数据类型为list),其中包含所有影片地区与影片发布年份数据,可视化部分可以使用“年份”字段做条形图、使用“国家”字段做世界地图,本项目使用“国家”字段做世界地图,关键代码如下:

# 影片地区与发布年份数据
def get_movie_label():
    """
    return: dict
    """
    label_data_list_year = []
    label_data_list_guoji = []
    label_dict = {}
    label_name = collection.find({}, {'标签': 1, '_id': 0})
    for x in label_name:
        if len(x["标签"][0]) == 4:
            label_data_list_year.append(x["标签"][0])
            label_data_list_guoji.append(x["标签"][1])

    label_dict["年份"] = label_data_list_year
    label_dict["国家"] = label_data_list_guoji

    return label_dict
导演参影数据查询

从数据库中查询导演列,(其中导演列中的数据类型为list),一个影片可能包含多个导演,将所有导演存入一个列表,返回包含所有导演的列表,数据可视化部分统计导演参影的top10数据,生成柱状图,关键代码如下:

# 导演参影数据返回
def get_movie_daoyan():
    """
    return: list
    """
    daoyan_data_list = []
    daoyan_name = collection.find({}, {'导演': 1, '_id': 0})
    for x in daoyan_name:
        for y in x["导演"]:
            daoyan_data_list.append(y)

    return daoyan_data_list
影片类型数据查询

从数据库中查询类型列,(其中类型列中的数据类型为list),一个影片可能包含多种类型,将所有类型存入一个列表,返回包含所有类型的列表,数据可视化部分过滤掉占比非常少的类型,生成饼图可以直观的看到网站内电影类型占比,关键代码如下:

# 影片类型占比分布
def get_movie_type():
    """
    return: list
    """
    type_data_list = []
    type_name = collection.find({}, {'类型': 1, '_id': 0})
    for x in type_name:
        for y in x["类型"]:
            type_data_list.append(y)

    return type_data_list
用户评论数据查询

从数据库中查询所有列,获取“【星辰影院】网友评价”的所有数据,将所有评论存入一个字符串,返回包含所有评论的字符串数据,在数据可视化部分使用jieba库分词,提取评论中的关键字,生成词云图,关键代码如下:

# 网友评论 整体拼接成字符串
def get_movie_remark():
    """
    return: string
    """
    remarks = ""
    remark_name = collection.find({})

    for x in remark_name:
        remark_sources = [x.get("【星辰影院】网友评价", "")] #所有评论插入列表
        for remark in remark_sources:
            if remark:
                remarks += remark

    return remarks
电影网站更新时间查询

从数据库中查询更新时间列,获取“更新时间”的所有数据,将所有数据以“-”分割获取月份数据,返回包含所有月份数据的字符串列表,在可视化部分生成折线图,关键代码如下:

# 电影网站更新时间分布
def get_movie_date():
    """
    return: list
    """
    data_list = []
    update_time = collection.find({}, {'更新时间': 1, '_id': 0})
    for i in update_time:
        data_list.append(i['更新时间'].split("-")[1])  # 获取月份数据
        
    return data_list

数据可视化实现

影片产地国家分布图

地图可视化数据获取,关键代码如下:

guojia = show_mongo_data.get_movie_label()["国家"]
city_data = [1] * len(show_mongo_data.get_movie_label()["国家"])

地图可视化效果,显示各国电影资源分布,如图所示。

导演参影Top10数量图

导演参影柱状图可视化数据获取,关键代码如下:

directors = show_mongo_data.get_movie_daoyan()
directors = [i for i in directors if len(i) > 0]
director_count = pd.Series(directors).value_counts().head(10)

导演参影柱状图效果,展示热门导演参影频率,如图所示。

影片类型占比饼图

影片类型饼图可视化数据获取,关键代码如下:

film_types = show_mongo_data.get_movie_type()
film_type_counts = pd.Series(film_types).value_counts().head(10)
data = [(index, count) for index, count in film_type_counts.items()]

影片类型占比饼图效果,反映网站内资源类型分布,如图所示。

用户评论关键词分析图

用户评论关键词词云图可视化数据获取,关键代码如下:

reviews = jieba.lcut(show_mongo_data.get_movie_remark())
word_counts = Counter(reviews)

#进一步清洗jieba库提取的数据
word_data = [(word, count) for word, count in word_counts.items() if
         len(word) > 1 and not re.match(r'^[a-zA-Z0-9]+$', word)]
word_data = [(word, count) for word, count in word_data if count > 5]
word_data = sorted(word_data, key=lambda x: x[1], reverse=True)[:500]

用户评论关键词词云图效果,生成词云图展示用户关注点,如图所示。

电影网站影片更新时间分布图

电影网站影片更新时间分布可视化数据获取,关键代码如下:

monther = dict(Counter(show_mongo_data.get_movie_date()))
dates = [f"2024-{item}" for item in monther.keys()]
yearly_counts = list(monther.values())

电影网站影片更新时间分布折线图效果,以折线图呈现更新规律,如图所示。

可视化大屏

自动化流程实现

使用git命令将代码推送到gitea代码仓库中,jenkins会读取gitea中的Jenkinsfile文件,并检查语法,通过后会自动运行stages中声明的shell脚本。

效果图

爬虫模块自动部署,效果图如图所示。

数据可视化模块自动部署,效果图如图所示。

Jenkinsfile流水线脚本代码

爬虫模块自动构建与部署,流水线脚本代码如下:

pipeline {
    agent any

    environment {
        IMAGE_NAME = 'cupfox_project'
        IMAGE_VERSION='v5'
        CONTAINER_NAME='cupfox'
        MONGO_CONTAINER_NETWORK='mongodb_data_set_db_network'
    }

    stages {
        stage('Build') {
            steps {
                echo "构建爬虫模块镜像..."
                sh 'docker build -t $IMAGE_HUB/$IMAGE_NAME:$IMAGE_VERSION .'
            }
        }

        stage('Push Image') {
            steps {
                echo "推送爬虫模块容器镜像到注册中心..."
                sh 'docker images $IMAGE_HUB/$IMAGE_NAME:$IMAGE_VERSION'
                sh 'docker push $IMAGE_HUB/$IMAGE_NAME:$IMAGE_VERSION'
            }
        }

        stage('Deploy') {
            steps {
                echo "部署爬虫模块到服务器..."
                // 停止并删除已存在的容器
                sh '''
                    docker ps -q -f name=$CONTAINER_NAME | xargs -r docker stop
                    docker ps -aq -f name=$CONTAINER_NAME | xargs -r docker rm
                '''
                // 启动新的容器
                sh 'docker run -id --network $MONGO_CONTAINER_NETWORK --name $CONTAINER_NAME  $IMAGE_HUB/$IMAGE_NAME:$IMAGE_VERSION'
                // 查看容器状态和日志
                sh 'docker ps -a'
                sh 'sleep 10'
                sh 'docker logs $CONTAINER_NAME'
            }
        }
    }
}

数据可视化模块,动态更新并快速发布,流水线脚本代码如下:

pipeline {
    agent any

    environment {
        IMAGE_NAME = 'cupfox_project_visuali'
        IMAGE_VERSION='v5'
        CONTAINER_NAME='cupfox_visuali'
        MONGO_CONTAINER_NETWORK='mongodb_data_set_db_network'
    }

    stages {
        stage('Build') {
            steps {
                echo "构建数据可视化模块镜像..."
                sh 'docker build -t $IMAGE_HUB/$IMAGE_NAME:$IMAGE_VERSION .'
            }
        }

        stage('Push Image') {
            steps {
                echo "推送数据可视化模块容器镜像到注册中心......"
                sh 'docker images $IMAGE_HUB/$IMAGE_NAME:$IMAGE_VERSION'
                sh 'docker push $IMAGE_HUB/$IMAGE_NAME:$IMAGE_VERSION'
            }
        }

        stage('Deploy') {
            steps {
                echo "部署数据可视化模块到服务器..."
                // 停止并删除已存在的容器
                sh '''
                    docker ps -q -f name=$CONTAINER_NAME | xargs -r docker stop
                    docker ps -aq -f name=$CONTAINER_NAME | xargs -r docker rm
                '''
                // 启动新的容器
                sh 'docker run -id  --network $MONGO_CONTAINER_NETWORK  --name $CONTAINER_NAME -p 38000:5000 $IMAGE_HUB/$IMAGE_NAME:$IMAGE_VERSION'
                // 查看容器状态和日志
                sh 'docker ps -a'
                sh 'sleep 10'
                sh 'docker logs $CONTAINER_NAME'
            }
        }
    }
}
Dockerfile编写

爬虫模块容器构建代码如下:

FROM python:3.8-slim-buster

COPY ./requirements.txt /data/


RUN apt-get update && apt-get install -y  net-tools \
    && pip install -r /data/requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ \
    && apt-get autoremove -y \
    && rm -rf /var/lib/apt/lists/* /root/.cache/pip


ENV MONGO_USERNAME="root"
ENV MONGO_PASSWORD="password123"
ENV MONGO_HOST="172.25.0.2"
ENV MONGO_PORT=27017
ENV MONGO_DB="cup_fox_movie"
ENV MONGO_TABLE="movie_data"

WORKDIR /data

COPY . /data/

ENTRYPOINT ["python", "-u", "/data/main.py"]

数据可视化模块容器构建代码如下:

FROM python:3.8-slim-buster

COPY ./requirements.txt /data/

RUN apt-get update && apt-get install -y  net-tools \
    && pip install -r /data/requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ \
    && apt-get autoremove -y \
    && rm -rf /var/lib/apt/lists/* /root/.cache/pip

ENV MONGO_USERNAME="root"
ENV MONGO_PASSWORD="password123"
ENV MONGO_HOST="172.25.0.3"
ENV MONGO_PORT=27017
ENV MONGO_DB="cup_fox_movie"
ENV MONGO_TABLE="movie_data"

WORKDIR /data

COPY . /data/

EXPOSE 5000

ENTRYPOINT ["python", "-u", "/data/app.py"]

NginxWeb服务器配置

配置文件

nginx反向代理服务器38000端口,重定向到443https端口,flask_38000.conf具体配置代码如下:


server {
    listen 80;
    server_name flask.localserver.local;

    location / {
        return 301 https://$host$request_uri;  # 将 HTTP 请求重定向到 HTTPS
    }
}

server {
    listen 443 ssl;
    server_name flask.localserver.local;

    ssl_certificate /etc/nginx/ssl/server.crt;  # 证书文件路径
    ssl_certificate_key /etc/nginx/ssl/server.key;  # 私钥文件路径

    ssl_session_cache shared:SSL:5m;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

    location / {
        proxy_pass http://127.0.0.1:38000; #反向代理到本地38000 Docker映射端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

数据可视化大屏

通过配置Nginx反向代理,将流量从HTTP重定向至HTTPS,提升安全性,修改本地hosts文件解析服务器IP到“flask.localserver.local”访问结果如图所示。


http://www.kler.cn/a/517742.html

相关文章:

  • C#,入门教程(05)——Visual Studio 2022源程序(源代码)自动排版的功能动画图示
  • CentOS 7 安装fail2ban hostdeny方式封禁ip —— 筑梦之路
  • Linux Futex学习笔记
  • 【AI日记】25.01.25
  • 万字长文总结前端开发知识---JavaScriptVue3Axios
  • 【2025年数学建模美赛F题】(顶刊论文绘图)模型代码+论文
  • 三代PacBio HiFi SV检测工具的安装
  • springboot基于spark的保险平台用户行为分析与研究
  • OpenAI Edge-TTS的使用方法
  • DAY5, 使用read 和 write 实现链表保存到文件,以及从文件加载数据到链表中的功能
  • 《Effective Java》学习笔记——第8部分 序列化
  • PyQt5菜单加多页签实现
  • Python爬虫之——Cookie存储器
  • Spring--SpringMVC的调用流程
  • 网关与云平台携手打造全轮转胶印机远程物联网监控系统
  • Spring Boot 后端跨域解决方案:解锁前后端通信的障碍
  • 使用python调用JIRA6 进行OAuth1认证获取AccessToken
  • 【u8g2模拟仿真】windows环境下使用sdl模拟仿真u8g2图形库
  • Ubuntu 顶部状态栏 配置,gnu扩展程序
  • FS飞速创新内推~
  • Windows中本地组策略编辑器gpedit.msc打不开/微软远程桌面无法复制粘贴
  • 【MySQL】我在广州学Mysql 系列——MySQL用户管理详解
  • SpringBoot Test详解
  • MySQL离线安装文档(Linux版)
  • 探索 SolidJS:一款高速的前端框架
  • 二叉树(了解)c++