问题背景:
为了分析北京二手房市场,需要爬取贝壳二手房数据()。 Shell的新村庄列表如下所示:
我需要的数据就是上图中绿线标记的部分。 分别是各新村名称、交易房数、出租房数、地区、分区、建设年份、单价、待售二手房。 列表数量。
在chrome中打开shell网站,通过分析网页的html内容,我们可以得到各个新村庄的文字如下:
可以看到每一项数据之间是用空格分隔的。 为了处理方便typescript 提取元素,我们对其进行分割操作:
通过对比,我们可以很容易找到字段中的元素与我们需要的数据的对应关系:
数组下标对应的数据的英文名称
我们希望最终的解析结果是这样的:
{
"name": "竹海水韵",
"sold": "15",
"forRent": "100",
"zone": "余杭",
"subzone": "闲林",
"builtYear": "2005",
"price": "23336",
"forSales": "255"
}
对比里面的字段和预期的结果对象,我们可以知道对于字段中的元素有两种处理方式:
完整返回(如名称、区域等);
解析出具体的数字并返回(如已售出、用于出租等)。
由上可以看出以下几个技术点:
所需数据维度(例如姓名)
数据维度对应的数组元素(需要知道元素的下标索引和元素的值)
该元素的变换函数映射
在 TypeScript 中,我们做了以下定义:
// 对数组元素进行转换
type map = (value: string) => string;
// 提取关键的数字
const extract: map = v => v.replace(/^.*?(d+)[套年元].*$/, '$1');
// 数据名称及其所对应的下标和转换函数
const field_mappings = {
name: [0], // 不需要转换
sold: [1, extract], // 需要转换
forRent: [2, extract],
zone: [3],
subzone: [4],
builtYear: [6, extract],
price: [7, extract],
forSales: [9, extract]
};
通过前面的配置typescript 提取元素,我们的新村庄对象可以定义如下:
type Area = {
[key in keyof typeof field_mappings]: string
}
关键点:其中typeof返回的是对象的类型,keyof返回的是该类型的所有key组成的类型集合,[key in xxx]表示Area的属性类型为xxx。 这些类型可以在开发者工具中观察到:
(类型)
(关键)
我们最终的解析函数如下所示:
// 将 文本字符串 解析为 小区对象
function parseArea(text: string): Area {
// 先将文本切割成数组
const items = text.trim().split(/s+/);
// 再将数组元素一个一个地转换为自己需要的数据
return Object.entries(field_mappings)
.reduce((p: Area, v) => {
// k是维度名称; idx是数组下标; map是转换函数
const [k, [idx, map]] = v;
p[k] = map ? map(items[idx]) : items[idx];
return p;
}, {});
}
Area的结构如下:
如果我们定义了一个变量 consta:Area,那么我们在开发工具中会得到如下手动补全提示:
这正是我们所期望的。
好吧。 如果您还有其他方法,欢迎留言。
发表评论