拓冰建站拓冰建站
首页 / 资讯中心 / 正文

南京二手房数据爬取与KMeans聚类分析实战

简介本资源是一份高分本科毕业设计项目面向计算机类专业学生如计科、人工智能、通信工程等及数据分析初学者聚焦南京二手房市场提供从数据采集到可视化与聚类分析的完整闭环实践方案。压缩包共158个文件含18个核心Python脚本实现链家爬虫、数据清洗与KMeans聚类、18个CSV数据文件含原始与清洗后多版本数据集、15个HTML可视化报告含交互式图表、65张分析结果PNG图及答辩PPT、README说明文档等整体40.01MB结构清晰、模块分明便于按流程学习或二次开发。已有171人下载学习所有代码均经实测运行成功配套文档详尽支持远程教学答疑。读者可直接复现全流程高效采集全量南京二手房数据完成缺失值处理与字段标准化生成房价热力图、区域分布散点图、户型/楼层/装修类型占比图并基于多维特征完成房源聚类输出可解释的购房参考分类是毕设、课程设计与数据分析实战的优质范例。1. 这不是又一个“爬链家画柱状图”的毕设——它用真实南京二手房数据跑通了从采集、清洗到聚类决策的完整闭环你可能见过几十个“Python爬虫matplotlib可视化”的毕设模板但真正能跑通「南京主城区2万套房源→字段缺失率超37%的原始CSV→清洗后保留18个有效维度→用KMeans轮廓系数确定最优聚类数→生成可解释的4类购房建议标签」的极少。这个项目不是演示型玩具它用requestsBeautifulSoup实打实抓取链家南京站2023年Q4全量挂牌页非API接口对单价、楼层、建成年代、装修、朝向、地铁距离等12个关键字段做分层清洗比如“高楼层”“中楼层”“低楼层”统一映射为数值区间“满五唯一”“不满二”等文本标签转为布尔特征再通过scikit-learn的KMeans与silhouette_score交叉验证最终输出的聚类结果能直接回答“预算300万、要求学区地铁、接受房龄15年以上”的用户该重点关注哪几类小区。适合计算机/人工智能专业学生复现毕设也适合想补全数据工程实战链路的初级数据工程师——它把“为什么清洗要分三步”“为什么聚类前必须标准化”“如何用箱线图定位异常单价”这些教科书里一笔带过的细节全写进了data_cleaning.py和clustering_analysis.py的注释里。2. 数据采集绕过链家反爬的三重校验用会话保持请求头轮换动态URL构造获取20000条真实房源2.1 链家南京站反爬机制解析与应对策略链家南京站lianjia.com/nj/ershoufang/对爬虫设置了三重防护① 请求头校验User-Agent、Referer、Accept-Language缺一不可② 会话级IP限频单IP每分钟超15次返回403③ 动态页面渲染部分房源信息由JavaScript异步加载。本项目未使用Selenium等重量级工具而是通过requests.Session()维持会话状态配合fake_useragent库动态生成浏览器标识并在每次请求间插入random.uniform(1.2, 2.8)秒随机延时。关键点在于所有请求必须携带Cookie: lianjia_uuidxxx该值从首页响应头中提取并复用否则后续页面返回空数据。项目中的crawler.py第42行明确写出session.headers.update({Cookie: flianjia_uuid{get_uuid_from_homepage(session)}})这是绕过基础校验的核心。2.2 分页URL构造与房源详情页批量抓取链家南京二手房列表页URL格式为https://nj.lianjia.com/ershoufang/pg{page}/但实际有效页数并非连续——项目通过while True循环状态码判断实现智能翻页当某页返回HTTP 200但div classno-result存在时终止。每个列表页解析出20-30个房源链接正则匹配href/ershoufang/[0-9]\.html再并发请求详情页。注意详情页中单价字段位于span classunitPriceValue标签内但部分页面该标签为空如待售状态此时需回退到总价/建筑面积计算建成年代字段藏在lispan classlabel建筑年代/spanspan classcontent2005年/span/li中需用re.search(r(\d{4})年, text)提取。以下代码片段展示了关键字段提取逻辑def parse_detail_page(html_content): soup BeautifulSoup(html_content, lxml) # 单价优先取unitPriceValue失败则用总价/面积计算 unit_price_elem soup.select_one(.unitPriceValue) if unit_price_elem: unit_price float(re.search(r(\d\.?\d*), unit_price_elem.text).group(1)) else: total_price float(re.search(r(\d\.?\d*), soup.select_one(.total).text).group(1)) area_text soup.select_one(.area .mainInfo).text area float(re.search(r(\d\.?\d*), area_text).group(1)) unit_price round(total_price / area, 2) # 建成年代从建筑年代标签提取 build_year None for li in soup.select(ul.list li): if 建筑年代 in li.text: year_match re.search(r(\d{4})年, li.text) if year_match: build_year int(year_match.group(1)) break return { unit_price: unit_price, build_year: build_year, district: soup.select_one(.xiaoquCardHeader .positionInfo a).text.strip() if soup.select_one(.xiaoquCardHeader .positionInfo a) else 未知 }提示ershoufang-origin-utf8.csv中第1278行出现单价0的异常记录是因对应房源详情页span classunitPriceValue标签被广告位遮挡导致解析失败。项目在data_cleaning.py第89行添加了if row[unit_price] 5000 or row[unit_price] 150000: drop_row()过滤逻辑避免污染后续分析。2.3 并发控制与异常重试机制为平衡效率与稳定性项目采用concurrent.futures.ThreadPoolExecutor(max_workers5)控制并发数。对失败请求实施三级重试① 网络超时requests.exceptions.Timeout立即重试② HTTP 403被限频等待random.randint(30, 60)秒后重试③ 解析失败如正则未匹配记录日志并跳过。crawler.py中fetch_with_retry函数封装了该逻辑其重试次数上限设为3次超过则写入failed_urls.log供人工核查。实测在南京本地宽带环境下单线程每分钟稳定抓取18-22页约400条房源5线程峰值达98页/分钟20000条数据总耗时约3.2小时。3. 数据清洗与特征工程从乱码CSV到可聚类的结构化数据表3.1 编码混乱与字段错位问题修复原始文件ershoufang-origin-ansi.csv存在严重编码问题Windows系统下用ANSI保存的CSV用UTF-8读取时中文显示为某区。项目通过chardet库自动检测编码raw_data open(file_path, rb).read(); encoding chardet.detect(raw_data)[encoding]再用对应编码读取。更棘手的是字段错位——链家页面中“装修情况”字段有时缺失导致后续所有字段右移一列。解决方案是在pandas.read_csv()中指定usecols参数强制读取固定列索引如[0,1,2,4,5,6,7,9,10,11,12,13]而非依赖列名。data_cleaning.py第33行定义了COLUMNS_MAPPING {0:title, 1:price, 2:area, 4:unit_price, ...}确保即使HTML结构微调字段位置仍可控。3.2 关键字段清洗规则详解清洗不是简单删空值而是基于业务逻辑重构。以floor字段为例原始值为“高楼层共32层”“底层共6层”项目将其转换为数值型floor_level1-32和分类型floor_category低/中/高floor_level: 提取括号内数字作为总层数结合“低/中/高”映射低楼层→1-3层中楼层→总层数×0.3~0.7区间高楼层→顶层向下3层floor_category: 用pd.cut()按floor_level分箱避免人工规则硬编码。同样subway_distance字段原始为“距3号线鸡鸣寺站500m”需用正则r(\d)m提取距离值对无地铁信息的记录填充np.nan后续用KNNImputer基于district和build_year插补。data_cleaning.py中clean_floor_column()函数完整实现了该逻辑包含边界处理如“顶层”映射为总层数“1楼”强制设为1。3.3 特征标准化与缺失值处理策略聚类前必须标准化但不同特征量纲差异极大unit_price范围5000-120000元/㎡build_year范围1980-2023年area范围40-300㎡。项目采用StandardScaler而非MinMaxScaler因后者会压缩build_year的年份跨度削弱时间维度区分度。缺失值处理分三类数值型unit_price,area用SimpleImputer(strategymedian)因中位数对异常值鲁棒分类型decoration,orientation用SimpleImputer(strategymost_frequent)地理型subway_distance先按行政区分组再用组内中位数填充。清洗后生成的ershoufang-clean-utf8-v1.1.csv包含18个字段其中price_per_sqm单价、age房龄2024-build_year、is_subway地铁距离≤1000m为True为新增衍生特征直接支撑后续聚类。4. 可视化分析与聚类建模用地理热力图轮廓系数验证四类购房群体4.1 核心指标可视化房价分布、房龄-单价散点图、地铁覆盖热力图可视化不堆砌图表聚焦决策支持。visualization.py中三个核心图南京房价地理热力图用folium加载南京GeoJSON边界Choropleth图层绑定district与mean_unit_price颜色深浅直观显示鼓楼均价42156元/㎡、建邺38920元/㎡等高价区房龄-单价散点图横轴age纵轴unit_price点大小映射area颜色映射decoration精装/简装/毛坯。图中明显呈现“房龄10年且精装”区域单价集中于5万/㎡“房龄20年”区域单价普遍3万/㎡地铁覆盖热力图将subway_distance≤500m的房源坐标经度/纬度输入HeatMap热点集中在新街口、夫子庙、河西CBD印证“地铁溢价”现象。# 房龄-单价散点图核心代码 plt.figure(figsize(10, 6)) scatter plt.scatter( df_clean[age], df_clean[unit_price], cdf_clean[decoration].map({精装: 0, 简装: 1, 毛坯: 2}), sdf_clean[area]/2, # 面积缩放避免点过大 alpha0.6, cmapviridis ) plt.colorbar(scatter, label装修类型 (0:精装, 1:简装, 2:毛坯)) plt.xlabel(房龄年) plt.ylabel(单价元/㎡) plt.title(南京二手房房龄与单价关系散点图) plt.grid(True, alpha0.3) plt.show()注意ershoufang-clean-utf8-v1.1.csv中longitude和latitude字段来自链家页面script标签内的resblockPosition变量解析时需re.search(rresblockPosition.*?(\d\.\d),(\d\.\d), html)提取精度达小数点后6位足够支撑市级热力图。4.2 KMeans聚类用轮廓系数确定最优K值并解读聚类结果聚类目标不是单纯分组而是生成可行动的购房建议。项目选取unit_price、age、area、subway_distance、is_subway、decorationone-hot编码6个特征经StandardScaler标准化后输入KMeans。关键步骤最优K值选择计算K2至K8的轮廓系数silhouette_scoreK4时得分为0.421最高显著高于K30.382和K50.356聚类中心解读K4的中心点显示Cluster 0低价老房均价2.1万/㎡房龄22年无地铁Cluster 1高价新房均价5.8万/㎡房龄3年地铁500m内精装Cluster 2中价次新房均价3.9万/㎡房龄8年地铁800m简装Cluster 3小户型刚需盘均价4.2万/㎡房龄12年地铁300m面积65㎡clustering_analysis.py第127行输出聚类报告Cluster 1占比12.3%平均总价428万元推荐给改善型买家Cluster 0占比31.7%平均总价215万元推荐给预算有限的首次置业者。4.3 聚类结果验证用PCA降维可视化与业务逻辑校验为验证聚类合理性项目用PCA(n_components2)将6维特征降至2D平面绘图。visualization.py中plot_pca_clusters()函数显示四个簇在PCA空间中分离清晰无重叠。更重要的是业务校验——随机抽样各簇100条房源人工比对链家页面Cluster 1房源全部位于河西、南部新城挂牌描述含“学区房”“品牌物业”“精装修交付”Cluster 0房源集中于迈皋桥、尧化门描述多为“满五唯一”“急售”“房东直租”。这证明聚类结果与真实市场分层一致非算法黑箱。答辩PPT中第14页即展示该PCA图与业务标签对照表成为评审专家认可的关键证据。5. 毕设落地技巧答辩高频问题应答、PPT设计逻辑、源码修改快速上手指南5.1 答辩必问的3个技术问题及应答要点评审老师最关注真实性与深度以下问题需脱稿回答Q爬虫如何应对链家JS渲染A我们确认链家列表页数据在HTML源码中静态存在查看Page Source可见div classinfo clear包含标题/价格/地址无需执行JS。仅详情页部分字段如“经纪人电话”需JS加载但本项目未采集该字段规避了复杂渲染问题。若需扩展建议用playwright替代requests。Q为什么选KMeans而非DBSCAN或层次聚类AKMeans在样本量大2万、特征维度适中6维时收敛快、可解释性强。DBSCAN对eps参数敏感南京房价空间分布不均匀易产生大量噪声点层次聚类计算复杂度O(n³)2万样本需32GB内存。我们实测KMeans训练时间1.2秒DBSCAN在相同硬件下超时。Q清洗规则是否主观如何保证客观性A所有规则均来自链家页面结构分析。例如floor清洗逻辑在crawler.py第156行有注释“依据链家UI规范‘高楼层’指总层数×0.7以上此定义见链家帮助中心文档v2.3第7节”。清洗脚本输出cleaning_report.txt记录每条规则应用次数如“装修字段标准化2187次”供复现验证。5.2 PPT设计用“问题-方法-证据”三段式替代功能罗列答辩PPT避免“第一章项目背景”改用场景化标题封面页直接放南京房价热力图标题“基于20000条真实数据的南京二手房聚类决策模型”问题页“购房者面临3大矛盾预算有限vs学区需求、房龄焦虑vs价格敏感、地铁便利vs居住品质”方法页用流程图展示“爬虫→清洗→特征工程→聚类→标签生成”箭头标注关键技术如“标准化Z-score”“聚类验证轮廓系数”证据页对比图——左侧原始数据unit_price直方图长尾分布右侧清洗后分布近似正态下方小字注明“异常值剔除率8.7%”。PPT中所有图表均来自visualization.py输出确保答辩时可现场运行代码生成最新图。5.3 源码修改速查表5分钟适配其他城市或新增分析维度若需扩展为苏州/杭州版本只需修改3处文件行号修改内容示例crawler.py28BASE_URLhttps://su.lianjia.com/ershoufang/crawler.py142district_list[工业园区,姑苏区,吴中区]data_cleaning.py201GEOCODING_API_KEY替换为高德地图苏州KEY若新增“学区评分”维度需在crawler.py中parse_detail_page()添加school_score soup.select_one(.xiaoquInfoItem .content).text if 学区 in soup.select_one(.xiaoquInfoItem .label).text else None在data_cleaning.py中clean_school_score()函数处理空值与文本标准化在clustering_analysis.py中FEATURE_COLUMNS列表末尾追加school_score。所有修改均不影响原有功能README.md已标注各模块职责新人可快速定位。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门