ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

猫眼电影Top100爬虫实战:数据清洗、分析与可视化完整指南

猫眼电影Top100爬虫实战:数据清洗、分析与可视化完整指南 简介这是一份基于Python的猫眼电影数据爬虫与分析可视化项目专为Python学习者、毕业设计、期末大作业及课程设计准备。项目自动爬取猫眼Top100电影将数据存入SQLite数据库并通过Flask框架结合Echarts、WordCloud等组件在网页端展示评分分布、票房分析、词云等效果包含首页、电影、评分、词云、关于等多个导航页面交互直观。项目涵盖数据采集、清洗入库、统计分析与可视化展示的完整流程代码注释详细新手也能看懂下载后简单部署即可运行。压缩包共85个文件主要由9个Python脚本、14个HTML页面、21个JavaScript文件、14个CSS样式文件构成另附数据库文件、启动脚本及项目配置类型齐全、结构清晰整个包仅1.06MB携带方便。目前已有651人学习/下载适合快速上手并作为高分项目参考也便于课程设计演示与二次开发。整体实现思路清晰对Python综合项目实践具有较高参考价值。1. 猫眼电影数据爬取从一个实战标题到一套可复用的分析流水线打开这个标题第一反应是“又一份爬虫教程”。但仔细看后半截数据分析加数据可视化才是这份代码的真正分量。猫眼电影榜单是国内电影市场最直接的风向标从上榜影片的评分分布、类型占比到票房区间能拆出来的业务问题远比“会爬”值钱。你拿到的是一份把“拿数—清洗—看规律”整条链路跑通的样本而不只是十几行requests代代码。这套方案的核心价值在于它是一个完整的参考实现先解决反爬拿到结构化数据再用pandas做字段清洗和统计最后用可视化把结论画出来。适合正在学爬虫但卡在数据清洗环节的人也适合想快速搭建“爬取—分析—展示”演示项目的开发者。需要注意的是猫眼的反爬策略一直在变代码里的UA池、代理配置和请求间隔才是真正值得反复调试的经验所在。2. 搭建爬取环境Python版本、依赖安装与反爬策略的选型思路2.1 环境准备的三个关键选择虚拟环境、requests还是Scrapy、解析库对比动手之前先把环境理清楚。Python版本建议3.9到3.11之间太老的版本对pandas和pyecharts的新接口支持不好太新的版本某些第三方库还没适配。我在Windows和Linux上都跑过这套流程Windows下主要注意编码问题Linux下则是依赖编译问题后面避坑章节会细说。# 创建独立虚拟环境避免污染全局Python python -m venv maoyan_env # Windows激活 maoyan_env\Scripts\activate # Linux/macOS激活 source maoyan_env/bin/activate # 安装核心依赖 pip install requests pandas matplotlib pyecharts lxml关于请求库的选择requests足够应对猫眼这种程度的反爬。Scrapy的并发和中间件机制更适合大规模爬取但学习曲线陡而且猫眼的接口频率限制很严格高并发反而容易触发封禁。做这个标题下的项目requests加适当延时已经足够选型原则是“够用就好别把简单问题复杂化”。2.2 UA伪装、代理池与请求间隔的基础配置猫眼对请求头检测比较敏感。默认的Python-requests标识会被直接拒绝伪装成浏览器请求是最基本的门槛。UA池至少要准备十来个不同浏览器的标识每次请求随机取一个这能大幅降低被识别为脚本的概率。代理池的优先级要看你的使用频率——如果只是跑一次拿几百条数据本机IP加合理延时就能过如果要频繁测试反爬策略那需要用免费代理池做轮换。# 请求头配置核心代码 import random import time import requests from fake_useragent import UserAgent # 初始化UA生成器自动模拟不同浏览器 ua UserAgent() def get_headers(): return { User-Agent: ua.random, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.8,en-US;q0.5,en;q0.3, Connection: keep-alive, }参数说明get_headers函数每次调用都会生成一个新的UA配合请求间隔使用效果更好。随机延时在1到3秒之间比较合适太短容易触发反爬太长会拖慢整体进度。如果你只爬Top100榜单整体耗时控制在五分钟左右即可。3. 猫眼电影Top100爬虫实现从HTML解析到字段清洗的完整链路3.1 为什么选择静态页面解析而非Ajax接口猫眼Top100榜单的初始页面是服务端渲染的HTML数据直接内嵌在DOM节点里用XPath或CSS选择器就能抽取不需要逆向JavaScript接口。Ajax接口虽然数据更干净但请求头需要额外的签名参数解析成本会翻倍。对榜单这种低频更新的数据静态页面解析是最稳妥的路径。另外还要考虑字符编码问题猫眼页面用的是UTF-8编码在requests请求中必须显式声明编码格式否则中文会直接乱码。# 请求与解析的完整代码 import requests from lxml import etree import pandas as pd import time def fetch_one_page(url): resp requests.get(url, headersget_headers(), timeout10) resp.encoding utf-8 # 返回HTML文本交给lxml解析 return etree.HTML(resp.text) def parse_top100(html): # 提取电影信息XPath定位到每个电影条目 dd_list html.xpath(//dl[classboard-wrapper]/dd) movies [] for dd in dd_list: title dd.xpath(.//p[classname]/a/title)[0] star dd.xpath(.//p[classstar]/text())[0].strip() release dd.xpath(.//p[classreleasetime]/text())[0] score dd.xpath(.//p[classscore]//text()) score .join(score) movies.append({ title: title, star: star, release: release, score: float(score) }) return movies # 主流程循环抓取10页 if __name__ __main__: all_movies [] base_url https://maoyan.com/board/4?offset{} for i in range(10): url base_url.format(i * 10) html fetch_one_page(url) movies parse_top100(html) all_movies.extend(movies) print(f第{i1}页抓取完成累计{len(all_movies)}条) time.sleep(random.uniform(1, 3)) # 保存为DataFrame df pd.DataFrame(all_movies) df.to_csv(maoyan_top100.csv, indexFalse, encodingutf-8-sig)逻辑说明fetch_one_page负责发起请求并返回解析后的HTML对象parse_top100用XPath定位每个电影条目。offset参数每页递增10对应榜单的分页逻辑。整个流程把请求和解析拆成独立函数方便后续替换请求头或增加异常处理。3.2 票房字段的归一化处理从“亿”和“万”到统一数值原始数据里的票房字段形如“票房3.2亿”字符串类型没法直接参与统计分析。处理方案是把单位拆出来统一折算成“万元”或“亿元”的数值型字段。这一步虽然简单但出错的频率最高——小数点位数、单位换算、缺失值处理任何一个地方不对后续的分析结果就会整体偏离。# 票房归一化处理示例 def parse_box_office(release_info): if 票房 not in release_info: return None # 提取数字和单位 value_str release_info.split()[1] if 亿 in value_str: value float(value_str.replace(亿, )) * 10000 elif 万 in value_str: value float(value_str.replace(万, )) else: value float(value_str) return value # 单位统一为万元参数说明解析逻辑把“亿”转成“万”作为统一单位输出数值类型方便参与聚合计算。没有票房信息的记录按NaN处理后续分析时可以用均值填充也可以直接剔除——这取决于你分析的重点。做Top100这类榜单分析我会先保留缺失值在分组聚合时再统一处理。4. 数据分析与可视化用pandas挖掘评分分布、类型特征与年份趋势4.1 基于pandas的数据清洗与分组聚合拿到csv文件只是第一步真正的分析从数据清洗开始。重复值剔除、缺失值填充、字段类型校正这三步做完才能得到一份可信的分析底座。主要关注四个维度的信息电影的评分分布情况主演阵容的队伍构成上映年份的分布规律以及票房和评分之间是否存在相关性。import pandas as pd df pd.read_csv(maoyan_top100.csv) # 数据清洗 df.drop_duplicates(subsettitle, inplaceTrue) # 提取上映年份 df[year] df[release].str.extract(r(\d{4})).astype(int) # 主演列表拆出第一主演 df[main_actor] df[star].str.extract(r主演(.)) df[main_actor] df[main_actor].str.split(,).str[0] # 分组聚合示例各年份的平均分和入榜影片数 year_stats df.groupby(year).agg( avg_score(score, mean), movie_count(title, count) ).reset_index() # 评分区间分布 score_bins pd.cut(df[score], bins[0, 7, 8, 9, 10], labels[7分以下, 7-8分, 8-9分, 9分以上]) score_dist df.groupby(score_bins, observedFalse).size().reset_index(namecount)这段代码里值得关注的是正则提取部分的写法(\d{4})直接取出字符串中的四位数字。用split拆主演列表时注意转义str.extract返回的是DataFrame不是Series配合astype做类型转换才不会踩坑。4.2 用matplotlib和pyecharts输出评分分布图、年份趋势图与票房数据看板静态分析报告用matplotlib就够交互式展示则用pyecharts更好。评分直方图和年份趋势折线图适合在博客或文档里展示票房对比的柱状图是项目汇报时最直观的证据。可视化原则是“一张图回答一个问题”——评分分布回答“榜单影片质量如何”年份趋势回答“近年是否更多好电影上榜”票房对比回答“高评分是否等于高票房”。import matplotlib.pyplot as plt import matplotlib # 防止中文乱码 matplotlib.rcParams[font.sans-serif] [SimHei] matplotlib.rcParams[axes.unicode_minus] False # 评分分布直方图 plt.figure(figsize(10, 6)) plt.hist(df[score], bins20, edgecolorblack, alpha0.7, color#2E86AB) plt.xlabel(评分) plt.ylabel(电影数量) plt.title(猫眼电影Top100评分分布) plt.grid(True, linestyle--, alpha0.3) plt.savefig(score_distribution.png, dpi150, bbox_inchestight) plt.show()注意rcParams里的axes.unicode_minus设置为False否则坐标轴的负号会显示为方块。如果是macOS或Linux环境SimHei字体不存在需要替换为系统中的中文字体名称这是跨平台最容易翻车的地方。4.3 场景化分析案例高评分电影是否也能拿下高票房用分组对比验证口碑和商业表现之间的关系。把评分分段与票房中位数做个交叉分析能一眼看出猫眼榜单上“叫好”和“叫座”是否重合。分析结论的表述要谨慎榜单只有100条样本能说明趋势但不能代表整个市场。# 评分区间与票房中位数对比 score_bins [0, 8, 8.5, 9, 10] labels [低于8分, 8-8.5分, 8.5-9分, 9分以上] df[score_level] pd.cut(df[score], binsscore_bins, labelslabels) # 票房单位已转为万元 pivot_table df.pivot_table( valuesbox_office, indexscore_level, aggfuncmedian ).reset_index() # 生成对比柱状图 plt.figure(figsize(10, 6)) plt.bar(pivot_table[score_level], pivot_table[box_office].astype(float), color[#E74C3C, #E67E22, #F1C40F, #2ECC71]) plt.xlabel(评分区间) plt.ylabel(票房中位数万元) plt.title(评分与票房表现的关系) plt.savefig(score_vs_boxoffice.png, dpi150, bbox_inchestight)pivot_table直接完成分组聚合省去了手动写groupby的步骤。astype(float)防止字符串拼接的问题这里如果数据里出现了NaN值绘图时会自动跳过但控制台会弹出警告不影响图表输出。5. 避坑指南爬虫与可视化实践中的7个高频翻车现场5.1 中文乱码问题现象爬取的数据在控制台显示正常写入csv后Excel打开全是乱码。原因Windows下Excel默认使用GBK编码读取文件而pandas写入时默认使用UTF-8。猫眼页面本身是UTF-8编码读取时声明了encodingutf-8但写文件时没注意系统差异。解决写入csv时指定encodingutf-8-sig带BOM头的UTF-8格式能被Excel正确识别。不要用utf-8直接写入那是在macOS和Linux上才表现正常的方案。5.2 lxml解析不到数据现象XPath语句在浏览器里能定位到元素代码里却返回空列表。原因浏览器开发者工具里的XPath是修正过的可能加了tbody等浏览器自动补充的标签。requests拿到的原始HTML里没有这些标签直接复制XPath就会失配。解决用etree.HTML加载后用//dl//dd这类相对路径不要用浏览器复制的绝对路径。先打印前100个字符确认HTML结构再写解析逻辑这个习惯能节省大量调试时间。5.3 请求被拒绝或返回状态码418现象连续请求十几条后服务器返回418或403状态码之后所有请求都被拒绝。原因触发频控。猫眼的反爬策略包括单位时间内的请求次数上限和IP维度封禁加上没有随机间隔的循环请求特征太明显。解决每次请求间sleep 1到3秒随机延时必要时在请求头加上Referer字段。如果IP已被临时封禁只能等几分钟再跑没有其他绕过手段。5.4 可视化中文显示为方框现象matplotlib生成的图片里中文标题和坐标轴标签全是方框。原因matplotlib默认字体不含中文字形需要在代码中重新指定。解决在绘图前设置字体Windows系统用SimHeimacOS用Arial Unicode MSLinux可以指定Noto Sans CJK SC。如果服务器上没有中文字体apt-get install fonts-noto-cjk安装后重启Python进程即可生效。5.5 Score为字符串导致聚合报错现象执行df.groupby(year)[score].mean()时抛出TypeError提示字符串不能求均值。原因从XPath提取的文本是字符串列表.join(score)得到的是类似“9.7”的字符串pandas不会自动转换类型。解决在写入DataFrame前用float()显式转换。如果数据已经写入csv读取后用pd.to_numeric(df[score], errorscoerce)统一转换无法转换的自动变成NaN。5.6 Python版本不一致导致依赖冲突现象本机Python 3.6能运行的项目换了3.12环境后pyecharts导入失败提示找不到某个模块。原因pyecharts新版重写了底层渲染逻辑旧接口被移除。解决在requirements.txt中锁定版本号pyecharts1.9.1和matplotlib3.5。创建虚拟环境时指定Python版本用python3.9 -m venv而不是python -m venv避免误用默认的3.12。5.7 猫眼页面结构更新导致XPath失效现象代码昨天还能跑今天返回的数据全是空值。原因网站前端改版DOM结构变化原有的XPath路径定位不到节点。解决重新打开页面审查元素查看当前结构。更好的方案是建立一层解析映射把XPath定义在配置字典里页面改版时只需修改dict的值不用改动主体逻辑——这就是“分析维度独立于实现”的好处。6. 进阶玩法使用代理IP池、实时榜单监控和导出Excel报告停了几天再跑代码大概率会发现之前写的UA池和延时策略已经不够用了。两个方向可以继续投入一个是把爬虫升级成监控脚本每天定时拉取榜单对比Top100的月度变化另一个是做代理池的准入测试用失效代理占比来评估数据源的稳定性。代理池的可用性验证用这个脚本把请求超时时间设为3秒依次测试每个代理的响应码成功的存入白名单。测试代理不花多少时间但能帮你筛选出能用的IP避免在做榜单历史数据分析的时候被卡住。这里的建议是把爬取结果直接写入SQLite比每天覆盖式存csv更利于后续的对比分析——数据量比以前大得多Excel文件本身就放不下多个日期的百条榜单数据了。基于历史数据的排序稳定性分析是一个值得尝试的分析方向可以用rank()函数求出每天的电影排名再计算排名的滑动标准差。如果某部电影的排名波动很大说明它的热度在下降。这些结论用pycharts的热力图来做可视化效果直观清晰。最后说个习惯每次改版后都把旧代码留个版本用注释标注好“2024年适用”之类的信息。猫眼的页面结构说变就变这些旧代码反而是排查失效原因的好参考能让你快速定位哪个字段解析出了问题。希望这个项目能帮你理解爬虫只是第一步真正值钱的是把原始数据变成可执行的判断。希望帮到你。本文还有配套的精品资源点击获取
返回列表