Python二手房数据采集与可视化分析毕业设计实战 简介这份资源是面向计算机、电子信息工程、数学等专业大学生的毕业设计与课程设计参考资料围绕Python二手房数据采集与可视化分析展开适合作为期末大作业或毕业设计的完整方案模板。压缩包共155个文件约35.13MB包含18个py脚本、18个csv数据集、15个html页面、11个js文件以及65张png图表另有pptx报告、md说明与ini配置等覆盖数据采集、清洗、存储、可视化到报告输出的完整链路。数据集提供原始与清洗后的多版本csv便于对比处理效果。目前已有841人学习下载说明该选题在同类项目中具有较高参考价值。读者可据此快速理解二手房数据的采集思路、字段清洗流程与可视化图表实现方式并参考报告PPT结构组织自己的论文与答辩材料适合具备一定Python基础、能自行调试与修改代码的学习者使用。1. 从一份二手房数据到能讲清的报告这套毕业设计到底在做什么二手房数据采集与可视化分析这个题目几乎每年毕业季都会被翻出来做一遍。原因很直接数据源相对好找业务逻辑人人都懂一点图表做出来也好看。但真正动手就会发现采集端要处理反爬和字段缺失分析端要面对重复房源、面积口径不一致、挂牌价与成交价混在一起这些脏活。这份毕业设计源码加数据集加报告PPT的组合核心价值不在于代码有多复杂而在于它把一条完整的链路跑通了从目标网站抓取房源字段清洗成结构化表格再用可视化把价格分布、区域热度、户型结构讲清楚。适合两类人一是时间紧、需要一套能跑通并改得动的计算机毕业设计同学二是想练手 Python 数据采集与 pandas 分析的入门者。下面按我实际做这类项目的顺序把每个环节拆开讲。2. 采集端怎么搭requests 加解析库的最小可用方案2.1 为什么选 requests BeautifulSoup 而不是上框架二手房列表页通常是服务端渲染的 HTML字段直接嵌在标签里用 requests 拿页面、BeautifulSoup 抽字段就够了。Scrapy 更适合大规模、多层级、需要去重调度的场景但对一个毕业设计来说引入框架反而增加调试成本。我的判断标准很简单如果目标站点单页就能拿到全部字段且总量在几千条以内requests 方案两三百行就能收工。真正要花心思的是请求头、翻页逻辑和字段容错而不是框架选型。2.2 最小采集脚本与字段抽取import requests from bs4 import BeautifulSoup import csv, time, random HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36, Accept-Language: zh-CN,zh;q0.9, } def parse_page(html): soup BeautifulSoup(html, html.parser) rows [] for item in soup.select(div.house-list-item): # 列表项容器按实际站点改 title item.select_one(h3 a) price item.select_one(span.total-price) area item.select_one(span.area) rows.append({ title: title.get_text(stripTrue) if title else , price: price.get_text(stripTrue) if price else , area: area.get_text(stripTrue) if area else , }) return rows def crawl(pages5): all_rows [] for p in range(1, pages 1): url fhttps://example.com/sale/pg{p}/ # 替换为目标站点分页规则 resp requests.get(url, headersHEADERS, timeout10) resp.encoding resp.apparent_encoding all_rows.extend(parse_page(resp.text)) time.sleep(random.uniform(1.5, 3.5)) # 随机间隔降低被封风险 return all_rows if __name__ __main__: data crawl(pages5) with open(houses.csv, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnames[title, price, area]) writer.writeheader() writer.writerows(data)这段代码的逻辑是先定义请求头伪装成正常浏览器再对每一页做 GET 请求用 BeautifulSoup 按 CSS 选择器定位列表项逐个抽取标题、总价、面积三个字段最后写入 CSV。参数上timeout10防止某个请求卡死拖垮整个脚本resp.apparent_encoding比写死 utf-8 更稳因为不同站点编码不统一random.uniform(1.5, 3.5)的随机间隔是血泪经验固定间隔的请求节奏太规律很容易触发风控。选择器div.house-list-item这类必须按目标站点实际 DOM 改不要照抄。2.3 翻页与字段容错的两个关键处理翻页有两种常见形态URL 里带页码参数或者下一页按钮的链接。前者直接拼 URL 最省事后者需要先解析出下一页 href 再请求。字段容错更重要——二手房列表里经常出现「暂无面积」「价格面议」这类文本如果直接float()转换会抛异常。稳妥做法是抽取阶段保留原始字符串清洗阶段再用正则提取数字提取不到就置为 NaN而不是在采集时就崩掉。另外标题里常混着「满五唯一」「近地铁」这类标签分析前要决定是保留还是剥离这直接影响后续户型字段的解析。3. 数据清洗把脏字符串变成能算的表格3.1 价格、面积、户型的标准化规则采集下来的字段几乎全是带单位的字符串比如「320万」「89.5平米」「3室2厅」。要参与统计就必须转成数值或结构化字段。价格统一转成万元面积统一转成平方米户型拆成室、厅两个整数列。这一步没有捷径只能针对实际数据写规则但规则要写得可复用别硬编码某一条记录。import pandas as pd import re df pd.read_csv(houses.csv) def to_price(s): if not isinstance(s, str): return None m re.search(r(\d(?:\.\d)?), s) return float(m.group(1)) if m else None def to_area(s): if not isinstance(s, str): return None m re.search(r(\d(?:\.\d)?), s) return float(m.group(1)) if m else None def split_layout(s): if not isinstance(s, str): return None, None m re.search(r(\d)室(\d)厅, s) return (int(m.group(1)), int(m.group(2))) if m else (None, None) df[price] df[title].apply(to_price) if price not in df else df[price].apply(to_price) df[area] df[area].apply(to_area) df[rooms], df[halls] zip(*df[title].apply(split_layout)) df[unit_price] (df[price] * 10000 / df[area]).round(0) # 元/平米 df df.dropna(subset[price, area]) df df[(df[area] 10) (df[area] 1000)] # 剔除异常面积 df.to_csv(houses_clean.csv, indexFalse, encodingutf-8-sig)逻辑说明三个转换函数都用正则提取第一个数字兼容「320万」「320.5万」这类写法。split_layout用捕获组同时拿到室和厅。unit_price是单价单位换算成元每平米这是后续分析最有价值的字段之一。参数上面积过滤区间(10, 1000)是经验值能滤掉明显录入错误dropna放在转换之后保证不会因为个别脏数据丢掉整行有效信息。3.2 去重与异常值两个最容易翻车的地方同一套房源可能因为重新挂牌出现多次标题和价格几乎一样。简单按标题去重会误杀稳妥做法是组合「小区名 面积 户型」做近似去重或者按标题相似度加价格接近度判断。异常值方面单价明显偏离区域均值的记录要单独看可能是别墅、商住两用或数据错误直接删会丢信息保留又会拉偏均值。我一般会先算分位数把超过 99 分位和低于 1 分位的记录单独导出人工核对而不是一刀切。4. 可视化分析让图表真正回答业务问题4.1 价格分布与区域对比怎么画才有信息量可视化最容易犯的错是「为了好看而画」。二手房分析真正要回答的是价格集中在哪个区间、哪些区域单价高、户型结构和总价是什么关系。价格分布用直方图加核密度曲线区域对比用箱线图比用柱状图更能看出离散程度。下面用 matplotlib 画两张核心图。import matplotlib.pyplot as plt import matplotlib matplotlib.rcParams[font.sans-serif] [SimHei] # 中文字体 matplotlib.rcParams[axes.unicode_minus] False df pd.read_csv(houses_clean.csv) fig, axes plt.subplots(1, 2, figsize(14, 5)) axes[0].hist(df[unit_price], bins40, color#4C72B0, edgecolorwhite) axes[0].set_title(单价分布) axes[0].set_xlabel(元/平米) axes[0].set_ylabel(房源数) df.boxplot(columnunit_price, bydistrict, axaxes[1], rot45) axes[1].set_title(各区域单价对比) axes[1].set_xlabel(区域) axes[1].set_ylabel(元/平米) plt.tight_layout() plt.savefig(price_analysis.png, dpi150)逻辑说明左图直方图看整体分布形态bins40是经验值太少看不出细节太多噪声大。右图箱线图按区域分组能同时看到中位数、四分位和离群点比柱状图信息密度高。参数上dpi150保证导出图片在报告里清晰中文字体必须设置否则标题全是方块这是新手最常见的翻车点。district字段需要在清洗阶段从标题或地址里解析出来如果原始数据没有就得补一步区域提取。4.2 户型与总价的关系用散点图找规律户型和总价的关系适合用散点图颜色区分区域能一眼看出哪些区域大户型集中。如果要做交互式图表pyecharts 是常见选择导出 HTML 嵌进报告 PPT 也方便。但要注意交互图在静态报告里展示效果有限答辩时现场演示更合适。静态图用 matplotlib 或 seaborn 足够别为了炫技堆一堆用不上的图表。5. 避坑与常见问题采集分析路上绕不开的五个坑5.1 请求被拒或返回空页面现象脚本跑几页后返回 403 或空 HTML。原因请求频率过高或请求头不完整被服务端识别为异常流量。解决补全 User-Agent、Referer、Accept 等头部加大随机间隔必要时降低单次采集页数分批次跑。5.2 中文字段乱码现象CSV 打开后中文全是乱码。原因写入编码和读取编码不一致。解决写 CSV 统一用utf-8-sigExcel 能正确识别读取时显式指定encodingutf-8-sig不要依赖默认值。5.3 价格转换后大量为空现象to_price返回一堆 None。原因部分记录价格写成「面议」「暂无」或藏在其他标签里。解决先统计空值比例如果超过两成说明选择器或字段定位有问题回去检查 DOM如果只是少量直接 dropna 即可别为个别记录改坏整体规则。5.4 图表中文显示成方块现象matplotlib 图上标题和标签全是方框。原因默认字体不含中文。解决设置font.sans-serif为 SimHei 或系统已有中文字体同时把axes.unicode_minus设为 False否则负号也会异常。5.5 分析结论和常识矛盾现象算出来的区域均价和实际感受差很远。原因样本偏差比如某区域只采到几套高价房源或者商住和住宅混在一起。解决按房源类型分层统计样本量过少的区域标注说明不要直接下结论。6. 从能跑到能讲报告与答辩的进阶处理代码跑通只是及格线毕业设计真正拉开差距的是能不能把数据讲成一个有逻辑的故事。我的习惯是先把清洗后的数据做几组交叉统计比如「区域 × 户型」的均价透视表再挑出三到四个反直觉的发现作为报告主线。比如某个远郊区域单价低但总价中位数不低原因是户型偏大这种结论比单纯说「A区比B区贵」有说服力得多。pivot df.pivot_table( valuesunit_price, indexdistrict, columnsrooms, aggfuncmedian ).round(0) print(pivot)这段透视表按区域和室数算单价中位数能快速定位「哪个区域哪种户型最贵」。用中位数而不是均值是为了避免少数高价房源拉偏结果。参数上aggfunc可以换成count看样本量样本太少的格子要谨慎解读。报告 PPT 的结构建议按「问题—数据—方法—发现—结论」走图表只放支撑结论的那几张不要把脚本里所有图都塞进去。答辩时最常被问的是数据来源合法性、样本量和清洗规则提前把这三块准备好。数据集和源码要保证能在他人的环境里跑通依赖版本写进 requirements路径用相对路径别写死自己电脑的绝对路径。我自己做这类项目最大的教训是一开始总想采集越多越好结果清洗阶段被脏数据拖垮后来改成先小批量跑通全流程再逐步扩大采集量效率反而高得多。数据采集与分析这件事跑通闭环比堆量重要。希望帮到你。本文还有配套的精品资源点击获取