简介这是一份面向毕业设计的Python网络爬虫实战资源主题为二手房源数据采集与可视化分析适用于高校计算机相关专业学生、爬虫初学者以及需要快速搭建同类系统的开发者。资源包内共157个文件压缩后大小约40.03MB结构上涵盖18个Python源码文件、18个CSV格式的房源数据、15个HTML可视化页面、11个JavaScript交互脚本、65张PNG分析图表并附有答辩PPT文档。其中CSV数据包含UTF-8与ANSI等多种编码的原始数据及清洗后的版本便于对比处理效果。目前已有693人学习下载。通过本包可获得从网页解析、数据清洗、存储到图表展示的完整实现思路能帮助读者直观理解二手房价格、区域分布等维度的分析过程同时提供可直接运行的代码和演示文稿节省从零搭建系统的时间也为毕业设计答辩提供了现成的展示材料。1. 二手房爬虫项目从采集到可视化的完整毕业设计想在一个城市买二手房最靠谱的做法不是跑线下门店而是先把挂牌数据拉下来做一轮分析。这个 python 网络爬虫二手房源数据采集及可视化分析毕业设计做的就是这件事从某房产平台抓取二手房源挂牌信息清洗后存成 CSV再用图表回答“哪个区域贵、哪个户型多、面积和总价是什么关系”。适合正在做数据类毕业设计、或者想练手完整爬虫流程的开发者——它不是一个只跑通一页的 Demo而是把“请求 → 解析 → 清洗 → 可视化”整条链路都串起来的项目源码和 PPT 文档都在包里拿到就能跑。2. 项目结构梳理六个 CSV 文件背后的设计意图2.1 从原始到清洗文件命名里的版本管理解压后最先看到的是六个 CSV 文件它们不是随机堆在一起的而是数据流水线的三个阶段产物。ershoufang-origin-utf8.csv和ershoufang-origin-ansi.csv是原始数据两个文件内容相同区别只在编码——一个 UTF-8一个 ANSI。这么做是有原因的Windows 上的 Excel 直接打开 UTF-8 会乱码ANSI 版本就是给这类场景准备的后悔药。ershoufang.csv是主数据集大约 20000 条记录文件名里那个空格是原作者的命名习惯读文件时注意别被坑。ershoufang - 20000.csv是它的备份副本数据量完全一致。真正有价值的是最后两个文件ershoufang-clean-utf8-v1.1.csv和ershoufang-clean-ansi-v1.1.csvv1.1 意味着清洗逻辑迭代过至少两次这两份才是拿来分析和可视化的最终输入。文件名作为版本号是我见过比较规范的毕设习惯。文件定位说明origin-utf8/ansi原始数据未清洗含缺失和脏字段ershoufang.csv主数据20000 条可直接读取clean-v1.1-utf8/ansi清洗结果类型已转换缺失已处理2.2 技术栈选型为什么不用 Scrapy 而用 requests技术栈用的是 Python requests BeautifulSoup pandas pyecharts这是国内数据类毕设里出现频率很高的组合。有人会问“爬虫为什么不上 Scrapy”实际原因是毕设的核心是“数据采集 分析”不是“分布式爬虫”。用 requests 同步请求、BeautifulSoup 解析代码更直白逻辑一层层看得见答辩的时候也更好讲清楚。pandas 负责数据清洗和结构变换可视化用的是 pyecharts它能生成带交互效果的 HTML 图表鼠标悬停能看到数值比 matplotlib 静态图更适合放进论文和 PPT。整体链路是requests 抓页面 → BeautifulSoup 提取字段 → pandas 清洗去重 → pyecharts 出图每一步都有明确的输入输出后期改任何一环都不影响其他模块。2.3 数据字段拆解爬下来到底有哪些字段从清洗表 v1.1 的列名看每条房源记录包含大约 10 个字段小区名称、所在区域、户型室厅卫、建筑面积、朝向、装修情况、楼层、总价、单价外加抓取时间。这些字段覆盖了二手房分析里最常用的维度区域和总价可以做价格分布户型和面积可以做供需结构朝向和装修则是楼层之外的重要价值因子。字段命名直接用了拼音像xiaoqu、quyu、huxing、mianji、chaoxiang、zhuangxiu、louceng、zongjia、danjia。这在毕设里很常见——少一层中英映射就少一类错误但也意味着如果你想把数据集迁移到自己的项目中列名重命名这一步绕不过去。清洗版还把原本混在字符串里的总价拆成了数值列这个细节会在后面第 4 章专门展开。3. 爬虫核心模块拆解一个请求从发出到入库的完整链路3.1 请求构造Header 伪装与 URL 参数规则爬虫部分的第一步是向目标站点发起请求。拿到代码后第一个看的就是请求函数它直接用 requests.get() 配合自定义 Header把 User-Agent 伪装成浏览器避免被服务器按默认 Python 请求头识别。代码里还写入了 Referer 字段——有一些站点的反爬逻辑会校验 Referer 是否来自自身域名漏掉这一项容易返回 403。def fetch_page(city_code, page_num): url fhttps://某平台.{city_code}.example.com/ershoufang/pg{page_num}/ headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://某平台.example.com/, } resp requests.get(url, headersheaders, timeout10) resp.encoding utf-8 return resp.text这个函数接收城市代码和页码两个参数拼出列表页 URL 并返回 HTML 字符串。timeout10是防止某个页面长时间无响应把整个抓取流程卡死resp.encoding手动指定 utf-8是为了绕开某些站点页面里没有声明 charset 导致的中文乱码问题。这里的pg{pagenum}/是市面上多数列表页的分页规律一页 30 条20000 条数据对应 700 页左右。3.2 页面解析BeautifulSoup 提取目标字段拿到 HTML 之后解析逻辑是对每一个li标签做字段定位。代码里用的是soup.select()方法按 class 选中每个房源卡片然后从中继续提取小区名、区域、户型、面积、朝向等字段。这里踩过的坑是CSS 选择器写得太死站点一旦改版升级class 名字一变整个 parse 函数直接崩掉。def parse_house_item(item): try: title item.select_one(.title a).text.strip() house_info item.select_one(.houseInfo).text.strip().split(|) total_price item.select_one(.totalPrice span).text.strip() unit_price item.select_one(.unitPrice span).text.strip() return { title: title, huxing: house_info[0], mianji: house_info[1].replace(平米, ), chaoxiang: house_info[2], zhuangxiu: house_info[3], louceng: house_info[4], zongjia: total_price, danjia: unit_price, crawl_time: time.strftime(%Y-%m-%d %H:%M:%S), } except AttributeError: return None解析时对每个字段的缺失都做了异常兜底AttributeError捕到就返回 None由后续的清洗步骤统一处理。house_info是从|分隔的字符串里切出的列表——这是各平台房源标题下常见的结构化文本切完后按位置索引所以任何一项为空都会导致整个列表顺序变化这种问题只有在后面清洗阶段才能暴露出来。3.3 多页抓取与数据落盘列表页循环抓取用的是for循环加range(1, total_pages 1)每页抓完调用time.sleep(random.uniform(2, 5))做随机延时。20000 条数据算下来硬跑也要半小时以上这属于正常的采集节奏。代码把每页解析结果直接追加到一个 list最后一次性用 pandas 转成 DataFrame 再to_csv()落盘。def crawl_all(city_code, total_pages): all_data [] for page in range(1, total_pages 1): html fetch_page(city_code, page) soup BeautifulSoup(html, lxml) items soup.select(.sellListContent li) for item in items: parsed parse_house_item(item) if parsed: all_data.append(parsed) time.sleep(random.uniform(2, 5)) df pd.DataFrame(all_data) df.to_csv(ershoufang.csv, indexFalse, encodingutf-8-sig)encodingutf-8-sig是核心细节——普通 utf-8 写入的 CSV 用 Excel 打开会乱码utf-8-sig会写入 BOM 头Excel 直接双击就能正确识别。这也是为什么后面清洗流程会多出 ansi 版本的另一个原因。每页抓完强制 sleep 2 到 5 秒是为了避免请求频率过高触发站点限流属于最基本的反反爬礼貌。4. 数据清洗与可视化从 20000 条脏数据到六张图表4.1 清洗逻辑类型转换与去重去脏原始 CSV 里总价是字符串带“万”字后缀单价则是“元/平”格式夹着数字和单位。清洗的第一步是用正则把纯数字抽出来再转成 float这样后面才能做聚合运算。同时同一套房子在列表页翻页时可能重复出现所以按标题加面积的组合键做去重避免统计时翻倍。def clean_data(df): df[zongjia] df[zongjia].str.replace(万, ).astype(float) df[danjia] df[danjia].str.replace(元/平, ).str.replace(,, ).astype(int) df[mianji] pd.to_numeric(df[mianji], errorscoerce) df df.dropna(subset[zongjia, mianji]) df df.drop_duplicates(subset[title, mianji], keepfirst) df df[df[zongjia] 0] df.to_csv(ershoufang-clean-v1.1.csv, indexFalse, encodingutf-8-sig)errorscoerce是 pandas 的容错开关遇到无法转成数字的值不会抛异常而是置为 NaN随后的dropna()统一清掉。单价里可能混入“暂无”这类文本状态也在这里一并处理。清洗完的 v1.1 文件和原始版本相比行数大约会少掉 3% 到 5%这部分差值在论文里可以作为“数据预处理效果”的量化证据。4.2 可视化设计区域均价、户型分布、面积价格关系可视化部分用 pyecharts 生成四个核心图表区域均价柱状图、户型占比饼图、总价散点图、单价热力图。区域均价图是按quyu分组对zongjia求均值倒序排列后输出能直接看出哪些区域挂牌价高户型饼图用huxing分组算数量占比三室永远是占比最大的主力户型。散点图的 X 轴是建筑面积、Y 轴是总价每个点是一套房源。这种图最能说明问题——绝大多数点落在一个斜向上的带状区域内说明面积和总价整体线性相关但总会有几个远离主趋势的离群点在答辩时解释这些点往往能加分。热力图进一步把单价按区域和户型两个维度做透视能回答“哪个区域的哪个户型最贵”这类跨维度问题这是单独看柱状图发现不了的。4.3 出图代码把 pandas 结果交给 pyechartsfrom pyecharts.charts import Bar, Pie, Scatter from pyecharts import options as opts region_price df.groupby(quyu)[zongjia].mean().sort_values() bar ( Bar() .add_xaxis(region_price.index.tolist()) .add_yaxis(平均总价(万), region_price.values.tolist()) .set_global_opts(title_optsopts.TitleOpts(title各区域二手房平均总价)) ) bar.render(region_price.html)Pie 和 Scatter 的写法完全同一套路add_xaxis和add_yaxis分别传入类别和数值最后render()生成独立 HTML。pyecharts 生成的图表是带交互效果的鼠标移上去显示数值图表右侧可以开关数据系列这一点比 matplotlib 更适合展示在毕业答辩现场。如果想把所有图表整合到一个页面还可以用Tab组件把四个图挂到一个 HTML 里做成一个简单的数据看板。5. 常见问题与排查跑通这套代码会踩的五个坑5.1 CSV 打开乱码编码声明不一致现象是把ershoufang.csv用 Excel 双击打开中文全部变成乱码或者用 pandas 读出来没问题但用记事本打开能看到奇怪的符号。原因有两个一是原始数据的页面本身是 UTF-8但读的时候用了系统默认的 GBK 编码二是to_csv()写文件时没加 BOM 头。解决方法是写入时固定用encodingutf-8-sig读取时用encodingutf-8这样一半的乱码问题直接消失。如果某些第三方工具只认 ANSI就用df.to_csv(path, encodinggbk)再导一份。项目里同时保留 utf-8 和 ansi 两套文件就是这个思路。5.2 爬取过程中途断掉没有断点续抓现象是程序跑到 300 多页的时候网络波动报错重新运行又从第 1 页开始。原因是代码里没有做增量断点逻辑所有数据都存在内存里进程一死就全丢。常见做法是每抓 50 页就把当前 list 追加写一次 CSV或者判断目标 CSV 已存在多少行从对应页再往下抓。我一般在for循环里加一个page_counter % 50 0的分支先落盘再继续这样最多丢 50 页的数据。5.3 页面字段被截断或换行符搅乱解析现象是house_info字符串用|split 之后某个字段里混入了\n或空格导致数组长度对不上解析出来错位。原因是 HTML 中某些房源标题带了换行标签.text提取时把换行符也抓进来了。解决方法是 split 之前先re.sub(r\s, , text)把所有不可见字符清掉再按|切割。血泪经验是这种问题往往在清洗阶段才暴露而报错信息完全定位不到爬虫代码只能在造数据时多做一步处理。5.4 平台反爬导致抓取数量不足 20000现象是跑完全程只拿到 6000 多条数据控制台没有任何报错。原因通常是请求频率过高触发服务器的验证码或跳转中介页。解决方法是把 sleep 时间从固定 2 秒改成 3 到 6 秒随机同时检查抓到的页面里是否还有房源li节点——如果连续 5 页解析出 0 条就说明已经被拦截需要停一下再继续。也可以在某次请求返回异常时打印状态码403 就等 60 秒这是我自己常用的降级策略。5.5 房源数据存在隐性重复现象是按title去重后数据量仍然偏多同一个小区的同户型房子被算成两套。原因是中介会在同一套房源标题里更换描述词比如改成“急售”“满五唯一”前缀。解决办法是去重键不要只用一个字段用小区 面积 总价三个字段组合判断或者把title去掉数字和形容词之后再做归一化去重。实际上去重是数据清洗里最花时间的一步做好这一步的可视化结果才有说服力。6. 二次开发把这套爬虫扩成自己的毕设或产品原型6.1 换成 Scrapy 架构从单脚本到工程化这套代码的核心逻辑全部在一个 Python 脚本里如果要扩展成科研项目或者简历上的亮点最值得做的就是迁到 Scrapy 框架。迁移的成本其实不高fetch_page变成start_requests()方法parse_house_item变成parse()回调多页循环用scrapy.Request()的callback参数驱动不用再手动管理 sleep。Scrapy 自带去重过滤和请求调度20000 条数据跑下来比 requests 循环版稳定很多还免费获得日志和统计报表。import scrapy class ErshoufangSpider(scrapy.Spider): name ershoufang start_urls [https://某平台.example.com/ershoufang/pg1/] def parse(self, response): for li in response.css(.sellListContent li): yield { title: li.css(.title a::text).get(), zongjia: li.css(.totalPrice span::text).get(), danjia: li.css(.unitPrice span::text).get(), } next_page response.xpath(//a[contains(text(),下一页)]/href).get() if next_page: yield scrapy.Request(response.urljoin(next_page))这段代码把原来的循环和 sleep 全部交给框架处理实际抓取速度反而更快因为 Scrapy 的下载器是异步的。挂在pipelines.py里的清理逻辑可以直接复用第 4 章的清洗函数最后scrapy crawl ershoufang -o output.csv一条命令出结果。6.2 增加地理编码让可视化上地图如果想让毕设跳出柱状图饼图的套路可以给每个小区加经纬度然后在地图上画气泡图。每一条房源记录里都有小区名和区域名用地理编码服务转成坐标即可转完再用 pyecharts 的Map类型做区域聚合热力图。地图可视化的效果远好于柱状图论文配图也更有质感。6.3 从描述统计走向预测模型数据集里的面积、总价、单价、区域、朝向、楼层已经足够支持做一个简单的房价预测模型。建议用 sklearn 里的线性回归或随机森林把区域和朝向做 one-hot 编码面积和楼层做数值特征预测目标设为总价。模型评估用 R 方和 MAE分数不用太高0.6 以上就能在论文里讲清楚“哪些特征对价格影响最大”这个分析结论。这是把爬虫项目从工具型升级成分析型的关键一步。我在做完这套改造之后最大的教训是先确认数据质量再谈模型和可视化原始数据里朝向字段有十几类写法“南北”和“南 北”在去重时会被当成两个值不处理干净后面的图表和模型全是错的。从那以后我每次拿到爬虫数据都会先info()和value_counts()检查一遍每个字段确认没有脏值再往下走。希望帮到你。本文还有配套的精品资源点击获取