前言
最近浏览到一些关于爬虫相关的文章,于是打算结合 ts 玩一下。整个爬取过程中看上去还是比较简单的,较为繁琐的在于使用 cheerio 解析页面的过程及存储数据(格式)问题【当然这里并没有存储到数据库】,其它地方还好。除此之外,还有一个问题:有很多网站其实设置了一些反爬机制,针对这样的网站又应如何去破解并顺利爬取信息呢?当然这个问题在本文并不会进行解答,相信在网上也可以找到一些答案,如果有兴趣的朋友我们也可以一起探讨探讨。
概述
爬虫的基本三部曲:获取页面数据、解析页面数据、数据内容存储
本文使用到的主要库的相应作用:
superagent获取页面数据 superagent【可以使用axios代替】cheerio解析页面数据 cheerio
爬取网站地址:voice.baidu.com/act/newpneu…
说明:
为什么选择使用 cheerio 而不直接使用 jQuery呢?在 node 下,如果使用 jQuery,需要结合使用 jsdom 库模拟一个 window 对象
项目初始化
创建项目文件夹并进入项目文件
mkdir spider-ts && cd ./spider-ts
项目初始化
npm init -y
安装需要的依赖包
npm i cheerio superagent @types/superagent typescript ts-node -D
初始化 ts 配置,会自动生成 tsconfig.json 配置文件
tsc --init
项目初始化基本就到这里了!下面主要讲述一下项目核心代码.
核心代码
getSpecifyData:解析页面数据获取所需内容信息
说明:$ 使用和 jQuery 类似,具体可查看 cheerio,可以通过选取元素获取所需信息
// 获取指定内容信息
const getSpecifyData = (html: string): Promise<string> => {
const $ = cheerio.load(html); // 加载 html
return new Promise((resolve, reject) => {
// 获取 html 页面第 12 个 script 标签第 1 个孩子 data 数据信息【指定内容信息】
if (($('script')[11]?.children[0] as any)?.data) {
const pageData = ($('script')[11]?.children[0] as any)?.data;
const sumData = JSON.parse(pageData); // 解析页面 JSON 数据
const updatedTime = formatDate(sumData.component[0].mapLastUpdatedTime); // 获取更新时间
const summaryDataIn = sumData.component[0].summaryDataIn; // 获取国内
const summaryDataOut = sumData.component[0].summaryDataOut; // 获取国外
const provinceData = sumData.component[0].caseList; // 获取省份
// formatDataInfo 格式化输出所需的数据类型
resolve(formatDataInfo({
updatedTime,
summaryDataIn,
summaryDataOut,
provinceData
}));
}
reject('获取数据失败');
});
}
formatDataInfo:获取所需数据按指定格式内容输出
说明:爬取到数据后我们可以通过实现一个 数据格式处理 函数来输出想要的数据信息
/**
* 格式化数据信息
* @param summaryData 需要格式化的数据信息
* @returns 格式化后的 JSON 数据
*/
const formatDataInfo = (data: Data) => {
const {
updatedTime,
summaryDataIn,
summaryDataOut,
provinceData
} = data;
let dataJson: DataJSON = {};
dataJson['数据更新时间'] = updatedTime;
dataJson['国内'] = returnDataType('国内', summaryDataIn);
dataJson['国外'] = returnDataType('国外', summaryDataOut);
// 循环省份数据并存入 dataJson
forEach(provinceData, (province: ProvinceData) => {
dataJson[province?.area] = returnDataType('省份', province);
dataJson[province?.area].subList = {};
// 循环省份下市区数据并存入 dataJson
forEach(province?.subList, (area: AreaData) => {
(dataJson[province?.area]?.subList)[area?.city] = returnDataType('市区', area)
})
})
return JSON.stringify(dataJson);
}
getHtmlContent获取内容函数
说明:实例化 Spider,通过在类 Spider 执行器中调用获取内容函数。该函数即是概述中提到的基本三部曲
getHtmlContent = async (url: string, getSpecifyData: GetSpecifyData) => {
// 1. 获取页面 html 信息
const html = await this.getHtmlByAxios(url);
// 2. 获取对应标签内容信息(可以适当处理输入内容格式)
const data = await getSpecifyData(html);
// 3. 内容写入文件
this.writeFile(data);
}
更多代码实现可以查看 项目地址 【后面如果网页改版的话,项目爬虫代码不再更新,因此可能会存在问题】