项目实训——大数据租房推荐智能体——地图通勤评分(六)
本次博客主要是实现map板块与爬虫crawler板块的对接以及完善工作。
一、初步问题分析
在接手任务 2.3(地图 POI 与通勤分析)之前,项目里已经有了一个能用的地图服务和一个能跑的爬虫模块,但它们之间没有任何联系——就像两个孤岛。
地图服务 `map_service.py` 里面有一个 `analyze_house_location(address)` 方法,它接收一个**完整的中文地址字符串**(比如"上海市浦东新区张江路100号"),然后调高德 API 做地理编码、搜周边 POI、算步行通勤。这个方法本身是好的。
爬虫模块那边,三只爬虫(链家、安居客、房天下)竞速抓取房源,返回的数据长这样:
{
"city": "jn",
"district": "lixia",
"location": "历下-千佛山-鲁能领秀城",
"price": "2800元/月",
"area": "89平米"
}
问题一眼就能看出来:地图服务要的是"济南市历下区千佛山路鲁能领秀城",爬虫给的是拼音缩写加短横线拼接。直接传进去,高德根本识别不了。
更麻烦的是,这三个爬虫各有各的格式习惯——链家用拼音缩写存城市名、安居客用中文、房天下干脆把 source 存成了 `"fang"`。如果每个调用方都要自己处理这些差异,代码很快就会失控。
二、核心思路:数据标准化层
与其让地图服务去适应爬虫的格式,或者反过来,更合理的做法是在两者之间加一个标准化层。这个层的职责很明确:把各种乱七八糟的输入统一成一种格式,让上下游各自只和这种标准格式打交道。
这样做有两个好处:
1. 爬虫端可以继续按自己的习惯输出,不用改;
2. 地图服务只认标准格式,不用关心数据源头是哪家。
标准化的具体策略是"先建查找表,再做字段清洗"。查找表利用了项目里已有的 `ajk_com_city_district_full_async.json`(这是之前预爬取的城市区域映射数据),从里面的 URL 反向提取出拼音缩写到中文名的映射关系——比如从 `https://jn.zu.anjuke.com/` 推断出 `"jn"` 对应 `"济南"`。再加上一些常见城市的手动补充,覆盖了主要场景。
字段清洗则比较简单:价格用正则 `\d+` 提取数字,面积去掉 `㎡`/`平米` 后缀,朝向去掉 `"朝"` 前缀,`"fang"` 映射为 `"房天下"`,标签统一用空格分隔。
三、地址构造:为什么不能简单拼接地址构造:为什么不能简单拼接
标准化之后的数据有 `city="济南"`、`district="历下"`、`location="历下-千佛山-鲁能领秀城"`。直觉上把它们拼起来就行——`"济南市" + "历下区" + "历下-千佛山-鲁能领秀城"`——但结果会是 `"济南市历下区历下-千佛山-鲁能领秀城"`,多了一个冗余的"历下"。
实际场景中,爬虫的 `location` 字段经常已经包含了区域名作为首段。所以地址构造器需要先检测 `location` 的首段是否和 `district` 重复,重复就去掉。这个逻辑虽然简单,但如果不处理,会给高德的地理编码带来歧义。
另外,所有地址都统一加 `"市"` 和 `"区"` 后缀,避免了"济南历下"这种不规范写法导致的地理编码失败。
四、地图服务的增量改造
原来的 `analyze_house_location()` 保持不变(保证已有的 `/map/analyze` 端点不受影响),在这个基础上增加了两个新方法:
- `enrich_listing()`:接收包含 `full_address` 的房源数据,调用 `analyze_house_location()`,把地图分析结果附加回原数据
- `enrich_batch()`:批量处理,每条之间加 150ms 间隔,防止触发高德 API 的 QPS 限制
同时在原有的通勤数据中补上了数值字段 `distance_meters` 和 `duration_minutes`。原来的输出只有格式化的 `"450米"` 和 `"5分钟"`,对展示够了,但评分模型需要的是可计算的具体数字。这两个字段用 `int` 类型返回,评分引擎可以直接拿来做数值比较。
周边配套数据也补上了 `bus_count`(公交站数量),之前只统计了地铁、医院、超市,公交被搜索了但没记数。
五、管线串联的意义
做完这些之后,整条数据链路变成了这样:
爬虫竞速 → 标准化 → 地址构造 → 地图富化 → 可供评分
每一步的输出都是下一步的输入,格式是确定的。这为任务 2.4 的评分模型准备好了数据基础——评分引擎不需要关心数据是哪来的,只需要关心 `map_data.commute.nearest_subway.duration_minutes` 是 5 还是 15。
六、实际效果验证
标准化器对三种爬虫格式的处理:
| 字段 | 链家输入 | 安居客输入 | 标准化输出 |
| city | `"jn"` | `"济南"` | `"济南"` |
| price | `"2800"` | `"2800元/月"` | `2800.0` |
| area | `"89平米"` | `"80㎡"` | `80.0~89.0` |
| source | `"链家"` | `"安居客"` | 不变 |
地址构造:`city="济南", district="历下", location="历下-千佛山-鲁能领秀城"` → `"济南市历下区千佛山鲁能领秀城"`(自动去除了重复的"历下")
地图富化后的数据包含了坐标(经纬度)、周边 POI 数量(地铁站/医院/超市/公交站各多少个)、最近地铁/公交的步行距离和时间(格式化和数值两种形式)。
更多推荐
所有评论(0)