Python二手房数据采集与可视化:毕业设计实战指南
简介面向Python课程设计或毕业设计的二手房数据采集与可视化分析项目源码与配套资料包特别适合高校学生完成期末大作业、毕业设计答辩时参考。项目完整覆盖数据采集、清洗、存储、分析与可视化全流程通过Requests、BeautifulSoup等网络爬虫库抓取链家、房天下等平台的房价、面积、地理位置等字段利用Pandas完成重复值去除、缺失值处理和数据格式转换并将结果写入SQLite、MySQL或MongoDB数据库随后借助Matplotlib、Seaborn、Plotly等工具以柱状图、折线图等图表清晰呈现各城市二手房价格分布、面积区间与趋势变化。整包为zip压缩包大小约48.05MB核心内容包含可运行的Python源码与全套PPT汇报资料既能直接用于答辩展示也便于二次改进扩展。目前已有691人学习下载适合希望快速搭建同类爬虫与可视化项目的Python学习者。1. 二手房数据采集与可视化分析一个毕业设计题目的真实分量答辩现场导师随口问一句“房源数据从哪抓的、抓了多少怎么证明可靠”不少同学当场卡壳。这个「基于 Python 的二手房数据采集及可视化分析」题目要的不是写个爬虫而是把整条链路走通选数据源、写采集脚本、清洗入库、做可视化分析用图表回答几个房价相关的实际问题最后把源码和 PPT 整理成能交付的毕业设计。它适合计算机、大数据、信息管理专业的本科生也适合想借完整项目练手 Python 数据分析的从业者。技术栈很常规requests、BeautifulSoup、pandas、Pyecharts 加 Matplotlib不玩冷门框架。真正拉开分数的是细节——字段设计有没有先行、单位有没有统一、每张图有没有配一句结论。下面按采集、清洗、可视化、避坑、交付的顺序把每一步的做法、参数和坑位讲透。2. 数据采集先定数据源与字段再写第一版爬虫采集是整个项目的起点也是最容易让新手一头扎进去出不来的环节。很多人打开链家首页就开写正则折腾两天发现页面改了个 class 名字就全废了。正确顺序是先选数据源再定字段清单最后才写采集代码。这一步想清楚了后面清洗、可视化、答辩都会轻松很多。2.1 数据源选型链家、贝壳、安居客、房天下怎么挑二手房数据平台就那几个看起来都能抓实际体验差别很大。按毕业设计里最常见的做法我列了一张对比表给你参考数据源页面形态反爬强度字段完整度适合程度链家静态 HTML 分页中等高含总价/单价/面积/朝向首选贝壳数据走接口 JSON较强接口带签名高数据最规整可选安居客动态渲染 登录墙强频繁验证码中不建议房天下静态混合弱字段较乱重复多备选我一般建议毕业设计首选链家。原因有三个第一列表页是纯静态 HTML用 requests 加 BeautifulSoup 就能解析不需要上 Selenium 这种重量级工具第二每套房子的总价、单价、面积、朝向、楼层、装修都集中在同一条记录里字段齐全不用跨页拼接第三URL 分页规律明显ershoufang/pg2、pg3这样逐页加号就行代码写起来没有玄学。贝壳的数据质量其实最好但数据是前端通过接口异步加载的 JSON带签名参数直接请求拿不到得先分析 XHR 再拼接参数对毕业设计来说复杂度偏高。安居客的反爬比较激进翻几页就弹验证码调试时间会被拖得很长我的血泪经验是别碰。房天下虽然好抓但列表页经常混入车位、商铺清洗阶段要多花不少时间。有一点底线必须守住只采集公开页面展示的房源信息控制采集频率数据仅用于课程设计与学术分析这是此类项目的通用前提。不要上高并发不要去绕验证码用随机延时把请求间隔拉开既保护目标站点也保护你自己的进度。2.2 字段清单先行先定分析目标再定抓什么写爬虫之前先把分析问题列出来。导师大概率会问“你想通过这批数据回答什么问题”这个问题列表就是你的字段设计依据。常见的分析目标有五个各行政区域的二手房均价差异面积与总价的相关系数户型结构的分布比例朝向、楼层对单价的影响总价段位的集中区间。围绕这五个问题字段清单自然就出来了小区、区域、板块、户型、面积、朝向、楼层、装修、总价、单价。每个字段都能在后续分析里对应一个用途没有一个是凑数的。区域和板块一定要单独采集因为后面可视化要做区域维度的聚合如果只有小区名区域信息还得靠地理编码去补非常麻烦。这里有个过来人的建议宁可多抓一个字段也不要少抓。链家列表页附带的“关注人数”“挂牌周期”这类字段答辩时拿“关注人数和总价的关系”做一个简单分析比单纯描述价格分布更能体现思考深度。但也不要贪多字段超过十五个清洗时每多一列就多一分出错的可能。采集阶段保留页面原始值不要在爬虫里做“总价除以面积乘一万换算单价”这种加工原始字段进库加工统一放到清洗阶段做口径才不会乱。2.3 最小爬虫requests BeautifulSoup 跑通第一页字段定了就动手。环境很简单按 Python 安装教程装好 3.8 以上的版本再pip install requests beautifulsoup4就行。下面这个脚本是采集一个城市多个行政区域列表页的最小实现重点看解析函数怎么写import requests from bs4 import BeautifulSoup HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9, } def parse_list_page(html): 解析链家二手房列表页返回房源字典列表 soup BeautifulSoup(html, html.parser) items soup.select(.sellListContent li .info) result [] for item in items: title_el item.select_one(.title a) if not title_el: # 页面结构变化时这一行会救你 continue house_info item.select_one(.houseInfo).get_text(stripTrue) pos item.select_one(.positionInfo) pos_text pos.get_text(stripTrue) if pos else tokens pos_text.split() # 常见格式小区名 区域 板块 total_el item.select_one(.totalPrice span) unit_el item.select_one(.unitPrice span) parts house_info.split(|) house { 标题: title_el.get_text(stripTrue), 小区: tokens[0] if tokens else , 区域: tokens[-2] if len(tokens) 2 else , 板块: tokens[-1] if len(tokens) 3 else , 户型: parts[0] if len(parts) 0 else , 面积: parts[1].replace(平米, ) if len(parts) 1 else , 朝向: parts[2] if len(parts) 2 else , 装修: parts[3] if len(parts) 3 else , 楼层: parts[4] if len(parts) 4 else , 总价: total_el.get_text(stripTrue) if total_el else , 单价: unit_el.get_text(stripTrue).replace(元/平, ) if unit_el else , } result.append(house) return result这套代码有个细节值得说明解析任何列表页先用soup.select定位房源条目容器再在每条里逐字段取值而不是正则一把梭。houseInfo的文本用竖线分隔按split(|)拆开就能拿到户型、面积、朝向、装修、楼层五个子字段这是链家这类平台的常见结构。所有get_text(stripTrue)都是为了同时去掉标签和首尾空白避免清洗阶段再做一轮字符串处理。接着是主流程逐页请求并把结果存盘import csv, time, random def save_to_csv(data, path): if not data: return with open(path, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnameslist(data[0].keys())) writer.writeheader() writer.writerows(data) def main(): city sh # 城市拼音sh 表示上海 regions [pudong, xuhui, minhang, putuo, jingan, huangpu] all_data [] for region in regions: for page in range(1, 6): # 每个区域抓前 5 页 url fhttps://{city}.lianjia.com/ershoufang/{region}/pg{page}/ try: resp requests.get(url, headersHEADERS, timeout10) if resp.status_code ! 200: print(f区域 {region} 第 {page} 页返回 {resp.status_code}) break all_data.extend(parse_list_page(resp.text)) print(f区域 {region} 第 {page} 页完成累计 {len(all_data)} 条) except requests.RequestException as e: print(f请求失败{e}) time.sleep(random.uniform(1, 3)) # 随机延时控制频率 save_to_csv(all_data, house_raw.csv) print(f共采集 {len(all_data)} 条已保存到 house_raw.csv) if __name__ __main__: main()这里的参数都是按“够用且不容易被反爬识别”的标准设的timeout10防止某个请求卡死拖垮整个任务time.sleep(random.uniform(1, 3))把请求间隔控制在 1 到 3 秒随机波动接近人工浏览的节奏每个区域抓 5 页约 150 条六个区域合计近千条对毕业论文的可视化分析完全够用。如果只是演示效果两个区域各 3 页也能跑通全流程。区域拼音要以链家网页 URL 里的实际字段为准打开网页点一个区域就能看到。保存文件时用encodingutf-8-sig这一步直接决定后续 Excel 打开 CSV 会不会乱码先留个印象第 5 章还会专门讲。跑通第一页是整条链路上最关键的里程碑。第一次运行可能因为选择器失效、请求头被识别等各种原因翻车遇到问题先打印resp.status_code和soup.title确认拿到的是不是目标页面再排查解析逻辑这个习惯能省掉大量调试时间。3. 数据清洗与存储把“能抓”变成“能用”采集完成只是拿到原料。爬下来的数据里一定有重复条目、缺失字段、类型错乱和单位不一致这类暗坑直接拿去画图会得到一堆不可信的结论。这一章讲清洗与存储目标是把原始 CSV 变成一个口径清晰、类型正确的 DataFrame再选一个答辩时讲得清楚的存储方式。3.1 清洗五连去重、类型、缺失、异常、文本我习惯用 pandas 一条流水线处理顺序固定为去重、类型转换、缺失值、异常值、文本规整。这个顺序有讲究先干掉重复数据后面的统计才不受干扰先转好类型缺失值和异常值才能用数值运算去判断。import pandas as pd df pd.read_csv(house_raw.csv) print(df.shape, df.dtypes) # 先看规模与类型不要急着洗 # 1) 去重同一条房源可能被多个区域页重复抓到 df df.drop_duplicates(subset[小区, 户型, 面积, 总价]) # 2) 类型转换面积、总价、单价全部转数值 df[面积] pd.to_numeric(df[面积], errorscoerce) df[总价] pd.to_numeric(df[总价], errorscoerce) df[单价] pd.to_numeric(df[单价], errorscoerce) # 3) 缺失值朝向缺失补“未知”单价缺失用总价/面积回填 df[朝向] df[朝向].fillna(未知) df[单价] df[单价].fillna(df[总价] / df[面积] * 10000) # 4) 异常值面积 20 平以下或 500 平以上总价低于 10 万多为录入错误 df df[(df[面积] 20) (df[面积] 500)] df df[(df[总价] 10)] # 5) 文本规整去掉区域名首尾空格统一装修文案 df[区域] df[区域].str.strip() df[装修] df[装修].str.replace(精装修, 精装).replace(简装修, 简装) df.to_csv(house_clean.csv, indexFalse, encodingutf-8-sig) print(df.describe())逐个参数说清楚。drop_duplicates的subset我选的是“小区 户型 面积 总价”四个字段组合这套组合在真实业务里足够标识“同一套房子”单用小区名会把同一小区不同楼栋的房源误删。pd.to_numeric加errorscoerce是关键页面上出现“暂无数据”这类文本时它会把该单元格置成 NaN而不是让整列转换直接报错这是数据采集项目里的标准防御写法。单价缺失回填时注意单位总价单位是万元单价单位是元/平方米所以回填公式里要乘 10000。异常值的边界不是拍脑袋定的而是依据房源真实分布在售住宅面积几乎没有低于 20 平的大于 500 平的多为别墅样本少且单价分布特殊会影响整体均值。答辩时老师问“边界为什么这么设”你答“先看 describe 的分布再结合城市实际情况定阈值”这就是加分的逻辑。清洗完务必跑一遍df.describe()如果“均价”在几万这个量级内浮动说明方向和单位都对了。3.2 存储选型CSV 够用SQLite 更好答辩清洗后的数据存哪里取决于数据量和答辩策略。三千条以内CSV 完全够用pandas 直接读Excel 也能打开检查零学习成本。但如果论文里要写“数据库设计”这一章或者想演示 SQL 查询就用 SQLite 落库一条代码就完成迁移import sqlite3 import pandas as pd df pd.read_csv(house_clean.csv) conn sqlite3.connect(house.db) df.to_sql(house, conn, if_existsreplace, indexFalse) conn.execute(CREATE INDEX idx_region ON house(区域);) conn.execute(CREATE INDEX idx_price ON house(总价);) conn.commit() conn.close()df.to_sql的if_existsreplace表示每次运行都重建表适合重复清洗的场景indexFalse保证不把 DataFrame 的索引写进去变成多余的一列。建两个索引是给答辩准备的谈资区域索引加速分组聚合总价索引加速区间查询这样“数据库设计”章节有实际内容而不是干巴巴写一句“建了索引”。SQLite 的好处是单文件、跨平台、零配置交材料时把house.db一起放进数据目录老师用任意 SQLite 工具都能打开复核。相比 MySQL不用装服务、不用配账号毕业设计的体量完全不需要引入更重的组件。3.3 清洗后自检先信数字再信图数据洗干净不等于数据可信。画图之前我的习惯是做三道自检每题都不超过三行代码# 自检 1全表统计信息是否有明显不合理值 print(df.describe()) # 自检 2按区域抽 3 条人工核对页面 sample df.groupby(区域).sample(3, random_state0) print(sample[[小区, 区域, 总价, 面积, 单价]]) # 自检 3确认清洗后没有残留重复 print(重复条数, df.duplicated(subset[小区, 户型, 面积, 总价]).sum())自检 2 值得展开groupby(区域).sample(3)每个区域随机抽 3 条打印出来然后打开链家对应区域的列表页人工核对这三条的总价、面积是否一致。抽样核对能发现一种很隐蔽的错误——解析字段错位。比如某个区域的页面 div 结构略有不同导致“朝向”被填成了“装修”describe 和重复检查都发现不了只有人工看几眼原始页面才能暴露。核对没问题再进可视化这时候画的每一张图才有底气写进论文。4. 可视化分析四张图把房价规律讲到老师点头数据准备就绪进入整个项目里视觉产出最高的一步。二手房数据分析的套路已经很成熟关键不是图的数量而是每张图能不能回答一个具体问题。这一章讲工具分工、四张必做图的实现以及从图到结论的“最后一公里”。4.1 工具分工Pyecharts 做交互演示、Matplotlib 做论文配图可视化这一步最常见的坑是工具混乱。Pyecharts 和 Matplotlib 不是二选一而是分工Pyecharts 生成交互式 HTML鼠标悬停能看到数值、支持缩放答辩演示时打开浏览器现场拖动效果比静态图好一截Matplotlib 配 Seaborn 生成静态 PNG适合插图进论文排版稳定、打印不糊。毕业设计通常两者都上README 里写清楚“演示打开 HTML论文插图用 PNG”。特别提醒版本问题。Pyecharts 0.5.x 时代的老教程满天飞而pip install pyecharts现在装的是 1.x两代 API 差异巨大新版用add_xaxis和add_yaxis老版用add()直接传数据拿老代码粘进来第一行就会报TypeError。安装后先跑一句python -c import pyecharts; print(pyecharts.__version__)确认版本凡是看到教程里.add()加字典传参的用法直接跳过。这是新手最容易翻车的点。4.2 四张必做的图区域均价、面积-总价、户型分布、朝向箱线图第一张是区域平均单价条形图回答“哪个区最贵”from pyecharts.charts import Bar from pyecharts import options as opts region_mean df.groupby(区域)[单价].mean().sort_values() bar ( Bar() .add_xaxis(region_mean.index.tolist()) .add_yaxis(平均单价元/㎡, region_mean.round(0).tolist()) .set_global_opts( title_optsopts.TitleOpts(title各区域二手房平均单价), xaxis_optsopts.AxisOpts(axislabel_optsopts.LabelOpts(rotate30)), ) ) bar.render(output/region_price.html)注意先groupby(区域)[单价].mean()再画图统计口径是“区域平均单价”而不是“区域总价求和”避免面积大的区天然占便宜。x 轴标签旋转 30 度是为了应对区域名偏长的场景如果标签仍然重叠把rotate调到 45。画图前先建好 output 目录代码里用os.makedirs(output, exist_okTrue)最省事。第二张是面积与总价的散点图回答“房子越大越贵吗”from pyecharts.charts import Scatter s ( Scatter() .add_xaxis(df[面积].tolist()) .add_yaxis(总价万元, df[总价].tolist()) .set_global_opts( title_optsopts.TitleOpts(title面积与总价散点图), xaxis_optsopts.AxisOpts(name面积㎡), yaxis_optsopts.AxisOpts(name总价万元), ) ) s.render(output/area_price.html)散点图能直观看出正相关但答辩时最好补一条回归线把相关性量化。常见做法是用numpy.polyfit拟合一次函数或者在 Matplotlib 里用seaborn.regplot一行出图。这里提前给你一个重点答辩老师几乎必问“相关系数是多少”所以df[面积].corr(df[总价])这个值要提前算好记在心里别临场现算。第三张是户型分布饼图第四张是朝向箱线图这一组放一起看户型和朝向对价格的影响from pyecharts.charts import Pie huxing_pair [list(z) for z in df[户型].value_counts().head(6).items()] pie ( Pie() .add(, huxing_pair, radius[40%, 70%]) .set_global_opts(title_optsopts.TitleOpts(title户型分布 Top6)) ) pie.render(output/huxing_pie.html) import seaborn as sns import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False order [东, 南, 西, 北] sns.boxplot(datadf, x朝向, y单价, orderorder) plt.title(不同朝向的单价分布) plt.tight_layout() plt.savefig(output/chaoxiang_box.png, dpi200)huxing_pair那行是 Pyecharts 1.x 的固定写法value_counts().head(6).items()生成“户型-数量”对列表取前 6 种避免饼图出现二十个小扇形。Matplotlib 的中文字体配置font.sans-serif必须写在画图之前否则标题会变成一排方框这是每个 Python 爬虫可视化项目都会遇到的坑第 5 章再细说。4.3 每张图都配一句“所以呢”图表是证据不是结论。把图往 PPT 里一贴就完事是答辩低分的重灾区。我的做法是每张图配一段三行的读图说明这张图展示了什么、发现了什么规律、规律可能的原因是什么。比如区域均价图读完写“黄浦、静安均价明显高于外环区域与城市中心区位一致”面积-总价散点图写“总价与面积呈明显正相关但 300 平以上房源样本稀疏结论对外环大户型参考意义有限”。最后这句“样本有限”非常加分它向老师传递一个信号你知道自己结论的边界在哪。如果追求效果还可以把四张图表组合成一个带选项卡的 HTML 页面用 Pyecharts 的Tab组件这就是检索量很高的“python 爬虫可视化界面”的轻量实现不需要额外学 Flask。Tab 组件三行代码tab Tab()、tab.add(bar, 区域均价)、tab.render(output/all.html)四张图并到一个文件里演示时点选项卡切换观感比逐个打开文件专业得多。5. 避坑排查从采集被拦到图表空白的 5 个真实案例这一章把整个项目里最容易踩、踩了又最浪费时间的五个问题单独拿出来每条按“现象、原因、解决”三步讲清楚。这些都是我前后带过几个类似项目之后总结出来的高频事故你在复现时大概率会至少遇到其中两三个。前四个集中在采集和展示环节最后一个藏在数据口径里往往到画图那天才暴露。5.1 请求头缺失导致 301 与 403现象代码写好运行后resp.status_code返回 301 或 403打印出的页面标题不是链家而是跳转提示页parse_list_page返回空列表爬虫跑完零条数据。原因requests 默认的User-Agent是python-requests/x.x平台反爬一眼就能识别这不是浏览器。301 通常是平台把你的请求重定向到验证页或首页403 则是直接拒绝访问。很多教程只让你设一个 UA但只设 UA 也有概率被拦因为平台还会校验 Accept 和 Accept-Language。解决从浏览器开发者工具 Network 面板复制完整的请求头至少包含User-Agent、Accept、Accept-Language三个字段并保持大小写一致。请求间隔设置在 1 秒以上用random.uniform(1, 3)随机波动。如果连续翻页仍然被拦说明触发频率限制停一分钟再继续而不是硬着头皮加并发。毕业设计的数据量几百条就够慢就是快。5.2 选择器全空页面结构和教程不一样现象soup.select(.sellListContent li .info)返回空列表程序不报错日志却显示累计 0 条。原因链家这类平台会不定期改版class 命名和 DOM 层级都会调整网上的教程代码大多基于某个时间点的页面结构直接照抄很容易失效。另一个容易被忽视的原因是请求被重定向到了登录页或安全验证页你解析的根本不是列表页。注意把选择器提取成文件顶部的常量改版时只改一处不要在循环里到处搜 class 名。解决定位问题分两步。第一步打印resp.status_code和soup.title确认拿到的是列表页还是跳转页第二步在浏览器里右键检查房源卡片的真实结构重新写选择器。解析每条记录时用if not title_el: continue这样的防御写法兜底单条结构异常不影响整批数据这是数据采集项目里的通用习惯。5.3 Excel 打开 CSV 全乱码现象采集完成用 Excel 直接双击打开house_raw.csv中文全部显示成乱码用 pandas 读同一份文件却完全正常。原因CSV 以 UTF-8 编码写入不含 BOM 头Excel 在中文系统下默认按 GBK 解码于是每个汉字都成了乱码。pandas 自带编码探测所以能正确读出这容易让人误以为是数据写坏了。解决写入时统一用encodingutf-8-sig这个编码会在文件头部写一个 BOM 标记Excel 识别到后自动按 UTF-8 解码。采集脚本和清洗脚本里所有to_csv和open都带上这个参数。另外保存路径最好用纯英文目录某些中文路径在跨设备拷贝后也可能引发编码问题。5.4 Pyecharts HTML 空白Matplotlib 中文变成方框现象bar.render(output.html)运行成功没报错浏览器打开却只有标题没有图表另一边 Matplotlib 出图后中文标题变成一排方框。原因Pyecharts 空白通常有两种一是生成路径含中文或特殊字符浏览器以file://方式加载本地资源时路径解析失败二是图表容器没有正确拿到数据常见于 pyecharts 版本和教程不匹配。Matplotlib 的方框是字体的锅默认字体 DejaVu Sans 不含中文字形标题和坐标轴标签全部显示不了。解决Pyecharts 的生成路径固定用英文图表统一放进output/目录。如果打开仍是空白用浏览器开发者工具 Console 看报错十有八九是 JS 资源加载路径问题。Matplotlib 在画图脚本顶部写两行固定配置plt.rcParams[font.sans-serif] [SimHei]和plt.rcParams[axes.unicode_minus] False前者指定中文字体后者防止负号显示成方块。如果在 Linux 或无中文字体的环境跑先安装 Noto Sans CJK 并把字体名写进配置。5.5 区域均价算出来上亿单位与类型错乱现象数据清洗后画区域均价图某几个区域均价高达几千万上亿或者df.describe()里总价均值是正常值的几百倍。原因几乎都是类型和单位混了。常见的是“单价”列没有转成数值astype(float)遇到“暂无数据”报错后改用errorscoerce但后续聚合时 NaN 参与计算导致结果异常另一种是总价单位万、单价单位元/平方米回填公式漏乘 10000把“万/平方米”当成“元/平方米”用了。解决清洗完第一件事跑df.dtypes确认三列价格都是float64再用df[df[单价] 10000]查一下有没有异常低的值正常城市均价不会低于一万这个量级查出来的样本就是单位问题的线索。回填公式写成df[总价] / df[面积] * 10000上一行注释写清楚“总价单位万元单价单位元/㎡”防止三天后自己回来看代码又迷糊。数据这行最怕的从来不是算法难而是口径乱单位统一这件事值得用一行注释写死。6. 交付与答辩源码、PPT 与演示的三项自检技巧最后一步不是写代码而是把成果变成老师能快速看懂、愿意给高分的交付物。项目源码和 PPT 文件是毕业设计的门面我见过数据做得不错、但源码目录乱到老师根本找不到入口的同学最后分数平平。三项自检技巧如下。6.1 源码包结构让老师五分钟看懂源码包的目录结构就是你的代码脸面。常见的规范结构是这样project/ ├── spider/ # 采集脚本 ├── clean/ # 清洗脚本 ├── analysis/ # 可视化脚本 ├── data/ # 原始与清洗后的数据 ├── output/ # 生成的 HTML 与 PNG └── README.md # 运行步骤与依赖说明README 里用三行写清楚“安装依赖、按顺序运行、产出在哪”依赖锁进requirements.txt。用 PyCharm 或 VS Code 打开项目根目录按 README 顺序跑一遍这就是老师复核你代码的标准路径。6.2 PPT 一页一图一句话PPT 的逻辑按“背景与问题、技术路线、数据采集、数据清洗、可视化分析、结论”六部分走每页最多一张核心图加一句话结论先给结论再解释过程。把采集到的原始条数、清洗后的有效条数标进图注严谨性一眼就能看出来。6.3 演示别现场爬数据最后一个技巧也是最大的教训答辩现场演示永远用离线数据不要当场跑爬虫。网络波动、反爬触发、页面改版任何一个环节出问题都会让演示卡壳而老师不会关心是你的网络不好还是脚本有 bug。提前把采集好的 CSV 和渲染好的 HTML 图表放进项目目录现场演示的脚本只跑清洗和可视化两部分保证六十秒内能看到完整产出。如果硬要展示采集过程用录好的屏控制在两分钟内。这套流程走完你拿到的不仅是一个能答辩的毕业设计更是一套“先定问题、再采数据、清洗先行、图配结论”的做事方法。我自己早年做第一个数据类项目时就栽在顺序上——先写了三天爬虫再回头想问题结果字段不够又回去重抓。后来养成先列问题和字段清单的习惯类似项目再没返过工。希望这一篇能帮你避开同样的弯路少熬几个夜把精力花在真正加分的地方希望帮到你。本文还有配套的精品资源点击获取