恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Python爬虫+数据分析+可视化:猫眼电影榜单采集与Flask展示全流程

  • 首页
  • 资讯中心
  • /
  • Python爬虫+数据分析+可视化:猫眼电影榜单采集与Flask展示全流程

相关资讯

基于YOLOv11和Django的学生行为检测系统实现详解 2026/10/18 12:01:57
C#模拟经营游戏源码解析:Unity生命周期与核心逻辑实战 2026/10/18 12:01:57
Java学生信息管理系统课程设计源码解析:Swing+JDBC+MySQL实践 2026/10/18 12:01:57

最新资讯

Aspose.Words 21.11 JDK17实战:Word转PDF原理与避坑指南
WPF无人机地面站开发实战:多线程通信与地图渲染避坑指南
C语言数据结构实操环境:可调试、可验证、可扩展的代码脚手架
Java+Netty实现IEC 104协议对接:帧结构、编解码与避坑指南
QLoRA实战:消费级显卡上微调百亿参数大模型的完整指南
协同过滤图书推荐系统:原理、代码与评估实现

今日推荐

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本周热门

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

Python爬虫+数据分析+可视化:猫眼电影榜单采集与Flask展示全流程

发布时间:2026/10/18 12:01:57
Python爬虫+数据分析+可视化:猫眼电影榜单采集与Flask展示全流程 简介基于Python实现猫眼电影数据爬取、数据分析与数据可视化的完整项目面向数据采集、清洗、存储、分析与展示全流程的初学者尤其适合作为高校Python数据分析类课程设计或期末大作业的参考方案。项目以猫眼电影榜单为数据源覆盖爬虫编写、结构化存储、指标统计与图表呈现等多个环节代码结构清晰并配有注释零基础亦可读通同时保留二次开发空间。资源包共42个文件包含11个Python脚本、9个编译后的pyc文件、5个前端HTML页面、5个JavaScript脚本、5个XML配置、1个SQL数据文件等压缩包仅428KB。除核心爬虫与可视化代码外还内置数据库脚本、项目配置说明及依赖清单便于快速复现运行环境目录按api、views、models、static、templates等模块划分逻辑层次明确。目前已有1984人学习下载。对于需要完整项目演示、代码讲解或高分结课报告支撑的读者这份资源能提供从数据抓取到可视化展示的闭环示例其项目结构、注释规范与实现思路均具有较强参考价值。1. 用Python把猫眼电影数据从“爬”到“看”一份能直接演示的期末大作业全流程期末大作业最怕的不是代码写不出来而是导师问“你的数据哪来的”“分析完了怎么展示”。这份基于Python的猫眼电影数据爬取数据分析数据可视化项目恰好把整条链路补齐了先爬取猫眼榜单数据并存入数据库再用pandas做聚合统计最后在Web页面里把评分分布、上映年份趋势用图表呈现出来。项目不是散乱的脚本堆砌而是按Flask工程组织的——有蓝图、数据模型、数据库迁移目录代码注释也够细小白能跟着跑通有基础的人可以拿它做二次开发。下面我从工程结构、爬虫实现、数据分析到避坑排查把这份资源拆开讲清楚。2. 工程结构与数据流先看懂Flask项目是怎么组织起来的2.1 目录拆解manager.py、config.py与api_1_0蓝图的职责拿到压缩包解压后先别急着跑命令花十分钟把目录结构过一遍后面排查问题会省很多时间。这个项目用的是Flask的工程化写法不是单文件app.py到底。核心入口在manager.py它本质上是Flask-Script的启动脚本负责加载配置、注册蓝图、初始化数据库。config.py存放配置项比如数据库连接地址、debug开关、爬虫请求间隔这类参数。api_1_0是一个蓝图目录里面按照views、utils、models、templates、static分模块组织把接口路由、业务逻辑、数据模型和页面模板分开了。打开manager.py会看到类似下面的启动逻辑from flask_script import Manager from app import create_app app create_app(default) manager Manager(app) if __name__ __main__: manager.run()这里create_app是工厂函数传入的default对应config.py里的开发配置。Manager来自flask-script支持python manager.py runserver这类命令行启动方式比直接app.run()更容易控制端口和调试模式。参数说明default是配置类的名称你可以在config.py里定义DevelopmentConfig、ProductionConfig等多个类启动时切换环境manager.run()会读取命令行参数比如-p 5000 -d分别指定端口和开启debug。实际跑项目时我一般先用python manager.py runserver -h 127.0.0.1 -p 5000固定本机调试避免局域网访问造成干扰。config.py里最常改的是SQLALCHEMY_DATABASE_URI默认可能是sqlite:///cat_eye.db也可以换成MySQL。如果换成MySQL要确保本地装了驱动并且把charsetutf8加上否则中文数据存储容易出乱码。DEBUG开关建议只在开发阶段开True演示答辩时关掉避免控制台刷SQL日志刷到看不清页面输出。2.2 数据模型的落库models.py里的表结构与字段设计爬虫抓下来的数据最终要落到数据库models.py定义了电影表的结构。这个项目用的是Flask-SQLAlchemy模型类继承db.Model字段类型和约束直接在类里声明。典型的电影表会包含这几个字段from flask_sqlalchemy import SQLAlchemy db SQLAlchemy() class Movie(db.Model): __tablename__ movies id db.Column(db.Integer, primary_keyTrue) name db.Column(db.String(128), uniqueTrue, indexTrue) star db.Column(db.String(64)) release_time db.Column(db.String(32)) score db.Column(db.Float)字段说明name设置了uniqueTrue和indexTrue这是防止同一部电影被爬虫重复插入的关键约束star是主演信息通常是一长串演员名所以用String(64)而不是Text方便做字符串匹配release_time保留原始字符串比如“2019-05-01”后续在分析阶段再转成datetime类型。score是浮点数存储评分值。这里用String存时间而不是DateTime是因为爬虫解析出来就是字符串格式先原样入库再统一清洗处理起来更灵活DB层不需要关心格式。项目里还有migrations目录和alembic.ini这是Flask-Migrate在管理数据库表结构变更。首次使用要执行python manager.py db init生成迁移目录然后python manager.py db migrate -m add movies table生成迁移脚本最后python manager.py db upgrade把表建到数据库。如果改了模型字段重复migrate和upgrade两步就行。注意alembic.ini里的脚本位置不要乱改script.py.mako是迁移模板文件一般不需要手工编辑。2.3 配置与启动config.py里有什么要改的参数config.py是整个项目运行的“总闸”。除了数据库地址和debug开关还有几个参数直接决定爬虫是否会被封。比如REQUEST_INTERVAL控制两次请求之间的间隔单位是秒DEFAULT_HEADERS可以放User-Agent和RefererPAGE_COUNT决定爬取多少页榜单数据。这些参数建议集中放在config.py的类属性里而不是散落在爬虫脚本中这样后期调参只需要改一处。一个常见的坑是项目里config.py是同时给Flask和爬虫模块用的但爬虫脚本如果用from config import Config方式导入要确保脚本运行时当前目录在项目根目录下。我习惯在爬虫脚本顶部写sys.path.append(os.path.dirname(__file__))避免从子目录启动时导入失败。另外config.py里如果定义了SECRET_KEY记得改成随机字符串不要用网上默认值这关系到Web表单和session的安全性。3. 爬虫模块实现从网页请求到清洗入库3.1 请求策略UA伪装、超时重试与编码处理爬虫部分的核心目标是把猫眼榜单页的电影名、主演、上映时间和评分抓下来。猫眼的榜单页是静态HTML结构用requests拿源码再配合正则或BeautifulSoup解析就够了不需要上Selenium。但请求策略必须做好否则抓几页就被限流。我的做法是headers里带上完整的User-Agent和Referer并设置超时时间和重试机制import time import requests def fetch_page(url, retry3): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36, Referer: https://www.maoyan.com/board/4 } for i in range(retry): try: r requests.get(url, headersheaders, timeout8) r.raise_for_status() return r.text except requests.RequestException: timeout 2 * (i 1) time.sleep(timeout) return None这段代码的逻辑是先定义请求头User-Agent模拟浏览器Referer声明来源页面retry参数控制重试次数每次失败后等待时间按2 * (i 1)递增避免连续重试被封。timeout8表示8秒内没响应就抛出异常。参数调整建议如果你在本地网络环境比较差可以把timeout调到15如果爬取速度被限制重试间隔可以改为random.uniform(3, 6)增加随机性。这里没用代理池因为这个项目目标只是抓Top100榜单数据量级很小做好上述策略就够用了。注意返回的r.text会按响应头里的charset自动解码如果出现乱码可以手动指定编码r.encoding utf-8。猫眼页面现在是UTF-8但如果从旧缓存拿数据可能会遇到编码不一致的情况编码统一在爬虫入口处设置最稳妥。3.2 解析与清洗正则表达式提取字段pandas去重补缺失拿到HTML源码后下一步是解析。猫眼Top100榜单的页面结构比较规整电影名在classname的p标签里主演在classstar上映时间在classreleasetime评分拆成整数和小数两个i标签。用正则表达式能一次性提取全部字段import re def parse_movies(html): pattern re.compile( rp classnamea href.*? title(?Pname.*?).*? rp classstar(?Pstar.*?)/p.*? rp classreleasetime(?Preleasetime.*?)/p.*? ri classinteger(?Pscore_int.*?)/i ri classfraction(?Pscore_frac.*?)/i, re.S ) movies [] for item in pattern.finditer(html): movies.append({ name: item.group(name).strip(), star: item.group(star).strip()[3:], # 去掉“主演”前缀 releasetime: item.group(releasetime).strip()[5:], # 去掉“上映时间” score: float(item.group(score_int) item.group(score_frac)) }) return movies这段正则用(?Pname...)命名分组提取数据re.S让.能匹配换行符因为标签之间可能有换行。star和releasetime取出来后用切片去掉了前缀文字。参数说明pattern.finditer(html)返回迭代器不会一次性把整个匹配结果加载进内存float(item.group(score_int) item.group(score_frac))把“8”和“9”拼接成“8.9”再转浮点数。这里有个小坑如果页面结构微调正则可能匹配不到所以解析后建议加一个校验比如if name and score:再入库。清洗这一步我习惯用pandas来兜底。爬取结果转成DataFrame后先drop_duplicates(subset[name])去重再把star里的空值填成“未知”最后用to_csv保存一份原始数据方便分析阶段直接读import pandas as pd df pd.DataFrame(movies) df.drop_duplicates(subsetname, inplaceTrue) df[star] df[star].fillna(未知) df[score] df[score].astype(float) df.to_csv(movies.csv, indexFalse, encodingutf-8-sig)参数说明drop_duplicates的subset可以传列表比如[name, release_time]防止同名但不同上映时间的电影被误删encodingutf-8-sig会写入BOM头Excel打开CSV不会乱码这是实际演示时非常实用的细节。3.3 入库与增量更新避免重复插入的常用做法爬虫跑完一轮后数据要写进数据库。最直接的方式是遍历DataFrame逐条insert但这样第二次运行时会产生大量重复记录。更稳妥的做法是利用数据库的unique约束配合INSERT OR IGNORE或先查询再插入from sqlalchemy.dialects.sqlite import insert as sqlite_insert def save_movies(movies): for m in movies: obj Movie.query.filter_by(namem[name]).first() if obj: continue movie Movie( namem[name], starm[star], release_timem[releasetime], scorem[score] ) db.session.add(movie) db.session.commit()这里先按name查一次存在就跳过不存在才新增。参数说明这种“先查后插”适合数据量小的情况逻辑直观如果数据量很大比如几十万条改成批量sqlite_insert会快得多。db.session.commit()一定要放在循环外每循环一次都commit会拖慢写入速度。另外release_time字段我建议存入原始字符串不要在这里转datetime因为分析阶段可能会对多种日期格式做兼容提前转换反而容易丢信息。入库完成后可以在manager.py里加一条命令封装爬虫流程比如python manager.py crawl这样答辩演示时只需要敲一条命令不用在交互式环境里来回粘贴代码。封装思路是给Manager增加一个crawl函数内部调用fetch_page、parse_movies、save_movies三步。4. 数据分析逻辑评分分布、年份趋势与类型偏好4.1 聚合统计用pandas计算评分均值与数量分布数据进入数据库后分析阶段就轻松了。先把库里的数据读成DataFrame再做分组聚合。这个项目的分析维度主要有三个按评分区间分段统计电影数量、按上映年份统计年度平均评分、按主演出现次数分析头部演员。第一类统计用pd.cut切分评分区间import pandas as pd df pd.read_sql(SELECT * FROM movies, engine) df[release_time] pd.to_datetime(df[release_time]) df[score_bin] pd.cut( df[score], bins[0, 7, 8, 9, 10], labels[低分, 中等, 高分, 顶级] ) score_dist df.groupby(score_bin, observedTrue)[name].count().reset_index()pd.cut的bins参数定义了五个区间边界即0分到7分、7到8分、8到9分、9到10分labels是区间名称数量必须比bins少一个。observedTrue是pandas 2.x版本对分组后的分类列推荐设置的参数避免警告。groupby后取name列做count得到每个区间的电影数量。这里要注意release_time用pd.to_datetime转换时如果原始字符串是“2019-05-01”这类标准格式pandas会自动识别但如果混入了“2019年5月”、空值等情况会直接报错所以转换前最好先df[release_time].replace(, pd.NaT)把空值统一处理。4.2 相关性洞察上映年份与评分的趋势关系第二个分析维度是看年份对评分的影响这能回答“最近几年高分电影变多了还是变少了”。做法是提取年份字段后分组求均值df[year] df[release_time].dt.year year_stats df.groupby(year)[score].agg([count, mean, median]) year_stats year_stats[year_stats[count] 5] year_stats[mean] year_stats[mean].round(2)参数说明agg([count, mean, median])同时计算三个聚合指标比多次调用mean()少扫一遍数据过滤count 5是为了排除那些只有一两部样本的年份避免均值被离群数据带偏。输出结果可以直接喂给前端图表也可以打印出来做答辩文案。这里要注意如果早年上映的电影样本极少年份分组会产生很多NaNround(2)会把NaN保留这不影响JSON输出但展示图表时要让前端忽略空值。4.3 分析结果落盘CSV、JSON与数据库回写分析结果最终要给Web页面展示所以得落成前端能直接读的格式。CSV适合做二次数据处理JSON适合直接给ECharts用。我一般会把每张图表需要的数据单独导出成JSONimport json year_stats.reset_index().to_json(output/year_stats.json, orientrecords, force_asciiFalse)参数说明orientrecords让输出结果是[{}, {}]这种记录数组正好对应前端图表的数据格式force_asciiFalse是关键否则中文会被转成\uXXXX转义序列虽然解析没问题但人眼看着费劲。如果后续数据库结构稳定也可以把聚合结果直接用SQL查询重算不落盘这样页面每次打开拿到的都是最新数据。两种方案的取舍是落盘适合爬虫和分析分开跑的流程查询重算适合Web服务和数据库在同一台机器上的部署方式。分析阶段还有一个隐藏价值点把star字段拆开来统计演员。star通常是“主演张三,李四,王五”用str.split()做分词后explode展开再统计出现频次能生成“最常出现的演员”图表。这个维度在答辩时很加分因为它体现了你对原始数据的二次处理能力而不仅仅是把爬下来的数据原样展示。5. 避坑排查请求被限流、迁移报错与中文字体三连5.1 现象爬了几页后返回空数据或者请求直接超时原因请求头不完整或者请求频率太快。猫眼对异常请求会有临时限流表现是响应正常但页面内容里没有电影列表有时直接返回验证页。解决确认User-Agent是完整的浏览器标识不能只写python-requests/2.31每次请求之间至少间隔1秒最好用time.sleep(random.uniform(1, 3))做随机延时。另外爬虫脚本第一次跑成功后不要立刻重复跑连续高频请求是触发限流的主要原因。如果已经被限流休息几分钟再试不要硬着头皮加大重试次数。5.2 现象python manager.py db upgrade报错“Target database is not up to date”原因migrations/versions目录里的迁移脚本和数据库当前状态不同步。常见的是你在两个环境下交替执行过db migrate生成了多个迁移文件但数据库里没有对应的alembic_version记录。解决先用python manager.py db current查看当前版本如果版本落后手动执行db upgrade heads强制迁移到最新版本。如果混乱到无法修复最省事的方法是把测试库删掉重新db upgrade但生产数据千万别这么干。我一般会保留migrations/versions只维护一条主迁移链避免多人协作时产生分叉。5.3 现象matplotlib画图时中文标签变成方块原因系统字体里没有包含中文字体或者matplotlib默认的字体列表里没有中文字体。虽然这个项目用ECharts展示页面图表但你如果用matplotlib做本地探索性分析同样会遇到这个问题。解决在绘图代码前手动指定字体import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei] plt.rcParams[axes.unicode_minus] False参数说明font.sans-serif设置字体族SimHei和Microsoft YaHei分别对应黑体和微软雅黑按顺序匹配axes.unicode_minusFalse解决了负号显示成方块的问题。如果你在服务器上运行且没装中文字体可以先执行fc-list :langzh查看可用字体找到后把完整路径传给font_manager。5.4 现象Flask debug模式下爬虫会被重复执行原因debug模式默认开启Werkzeug的reloader代码有改动时自动重启进程如果爬虫代码写在启动流程里每重启一次就爬一轮。解决把爬虫逻辑独立成脚本不挂载在manager.py的启动路径上如果非要在Flask请求里触发爬虫确保app.run(debugTrue, use_reloaderFalse)这样就不会自动重启。实际开发中我更喜欢用flask cli注册一个独立的crawl命令手动触发爬取调试时只跑runserver两者互不干扰。5.5 现象pandas读取CSV报UnicodeDecodeError或者Excel打开中文乱码原因写入时用了utf-8但pandas默认读取编码是系统区域设置Windows下可能是gbk导致解码失败。解决写入时统一用encodingutf-8-sig读取时也指定encodingutf-8-sig。注意utf-8-sig和utf-8的区别前者会写入BOM头Excel能正确识别UTF-8编码而纯utf-8在Windows下容易被解读成gbk。如果已经有乱码文件先用文本编辑器把内容转存为UTF-8 with BOM格式再重新读取。6. 可视化与进阶从静态图表到交互看板6.1 在Flask中复用分析结果接口返回JSON给前端渲染数据分析的结果不是纸上谈兵最终要展示在页面上。项目里templates和static目录就是干这个的。我建议把分析结果通过Flask接口暴露给前端让页面加载时动态请求数据而不是把数据硬编码在模板里。新建一个蓝图视图函数from flask import jsonify from models import Movie import pandas as pd api.route(/stats/year) def year_stats(): rows Movie.query.all() df pd.DataFrame([{ release_time: r.release_time, score: r.score } for r in rows]) df[year] pd.to_datetime(df[release_time]).dt.year result df.groupby(year)[score].mean().round(2).reset_index() return jsonify(result.to_dict(orientrecords))这段代码把SQLAlchemy查询结果转成DataFrame再聚合最后输出JSON。参数说明to_dict(orientrecords)输出记录数组round(2)限制小数位。相比直接读CSV实时查询的好处是爬虫跑完后刷新页面就能看到新数据不需要重新执行分析脚本。前端模板里用ECharts发起fetch(/api/stats/year)请求拿到的数组直接传给setOption即可。6.2 从单次爬虫到增量更新简单定时任务如果你不想每次手动跑爬虫可以用APScheduler加一个定时任务每小时或每天抓一次增量数据。注意增量爬取要配合第3.3节的去重逻辑否则会越攒越多。一个轻量做法是在manager.py里初始化schedulerfrom apscheduler.schedulers.blocking import BlockingScheduler def start_scheduler(): scheduler BlockingScheduler() scheduler.add_job(run_crawler, interval, hours6) scheduler.start()这里interval触发器按固定间隔执行适合榜单这类更新频率较低的数据源如果你只需要在答辩当天跑一次把调度器去掉用python manager.py crawl手动执行更可控。定时任务有一个隐藏问题进程必须一直运行如果部署在云服务器上要确保进程守护工具不会杀掉它。6.3 扩展方向把评分分布做成可筛选的交互图表如果你想让这个项目在答辩中更亮眼把静态柱状图升级成可筛选的交互图。比如在ECharts里加一个dataZoom组件让观众拖动查看不同年份区间的评分变化或者用tooltip联动显示该年份下的Top5电影。前端改动其实不大后端接口只需要额外返回一个top_movies字段。这个扩展不需要引入新的依赖但会明显提升演示效果。从那以后我每次做爬虫分析和可视化的项目都会强制把爬虫、分析、展示拆成三个独立模块先单独验证数据落库再启动Web服务看页面避免调试时互相干扰。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号