今天应该是爬虫的最後一篇了。我们要把爬下来的资料做成「每日铁人赛热门 Top 10」。
// 2021-09-26.json
{
"12": [
{
"type": "Modern Web",
"series": "JavaScript Easy Go!",
"title": "#1 JavaScript Easy Go!",
"link": "https://ithelp.ithome.com.tw/articles/10264088",
"author":"JacobLinCool",
"date": [2021, 9, 15],
"view": 1286,
"team": "NTNU-Unic0rn"
},
...
],
"16": [
...
],
...
}
资料的格式:
type
, series
, title
, link
, author
, date
, view
, team
值team
会是 null
其实我们会发现这样ˋ抓下来很多资料会重复,如果把文章资料分开存可以减少储存空间消耗,但在这里我们不再做资料格式的优化了,直接来处理资料。
我们想要做出来的东西是像这样的:
需要计算的东西其实就只有一项:观看增加值。
其他东西都只要从资料中抓出来就可以了!
先让我们建立一个新档案 report.js。
const fs = require("fs"); // 我们会需要 fs 来操作爬虫爬到的档案
const firstFilename = process.argv[2]; // 用 process.argv 来拿到要比较档案的位置
const secondFilename = process.argv[3];
if (firstFilename && secondFilename) {
const [date1, date2] = [getDate(firstFilename), getDate(secondFilename)]; // 从档名推论日期
const [d1, d2] = [getLatest(firstFilename), getLatest(secondFilename)]; // 拿到档案中最新的资料
const result = calcDiff(d1, d2); // 计算差值
const report = genReport(result, date1, date2); // 根据结果产生报告
console.log(report); // 印出报告
} else { // 如果执行时没有给两个要比较的档案位置,则提示使用方法
console.log("Usage: node report.js [day1 file path] [day2 file path]");
}
跟爬虫一样,我们需要先引入 fs 来做档案操作。
接着从 process.agrv 中拿取要比较的两个档案位置, process.argv 会储存从 Terminal 执行时的参数。
如果我们在 Terminal 这样呼叫:
node report.js file1.json file2.json
则 process.agrv 就会是这样:
["Node.js 的位置", "report.js 的位置", "file1.json", "file2.json"]
如果使用者有正确操作程序的话,程序就可以正常的产出报告;反之,则提醒使用者程序的正确使用方法。
接下来将分别说明各用到的函式
getDate
函式的任务是将档名转成日期。
function getDate(filename) {
const name = filename.split(/[\\/]/).pop().split(".")[0];
const [year, month, day] = name.split("-");
return [year, month, day];
}
filename.split(/[\\/]/).pop()
会得到不含路径的单纯档案名称,接着再用 .split(".")[0]
来拿到附档名以外的 YYYY-MM-DD
格式,最後用 .split("-")
分割年月日。
getLatest
函式的任务则是从档案中找到拥有最多文章的那个时间及资料,应该也就是「最新」的资料。
function getLatest(filename) {
const file = fs.readFileSync(filename, "utf8");
const json = JSON.parse(file);
const [time, data] = Object.entries(json).sort(([k1, v1], [k2, v2]) => v2.length - v1.length)[0];
return { time, data };
}
我们先读取档案并将其从文字转成 Object。
接着用 Object.entries
转成阵列再依文章数做降幂排序并使用第一个时间的资料。
calcDiff
负责计算两笔数据之间的差值,并依差值大小排序。
function calcDiff(d1, d2) {
const { data: data1, time: time1 } = d1;
const { data: data2, time: time2 } = d2;
const _index = data1.reduce((acc, curr, idx) => {
acc[curr.link] = idx;
return acc;
}, {});
const diff = data2.map((item) => {
const d = _index[item.link] !== undefined ? item.view - data1[_index[item.link]].view : item.view;
return { ...item, diff: d };
});
return { data: diff.sort((a, b) => b.diff - a.diff), time: [time1, time2] };
}
注意:在这里的 d1
d2
的 d 表示倾向於 data 而非 day 或 date。
我们先解构两笔数据的时间及资料拉出 data1
data2
time1
time2
。
接着用 reduce
制作一个 data1
的临时字典,让我们之後在计算时能依照 data2
资料中的文章网址快速取得同文章於 data1
之数据。
接着遍历 data2
来计算差值。
最後回传时顺便执行对差值的降幂排序。
genReport
顾名思义就是产生报告用的,因为 iThelp 文章是用 Markdown,所以报告也是产生 MD 语法。
function genReport(result, date1, date2) {
const { data, time } = result;
const articles = data.splice(0, 10);
let report = `-----\n## 每日铁人赛热门 Top 10 (${date1[1]}${date1[2]})\n以 ${+date1[1]}/${date1[2]} ${time[0]}:00 ~ ${+date2[1]}/${date2[2]} ${time[1]}:00 文章观看数增加值排名\n\n`;
articles.forEach((item, idx) => {
report += `${idx + 1}. \`+${item.diff}\` [${item.title}](${item.link})\n * 作者: ${item.author}\n * 系列:${item.series}\n`;
});
return report;
}
我们用 splice(0, 10)
来取得已排序资料的前 10 名。
report
则先用 Template 产生一些没什麽用的资讯。
然後遍历前 10 文章并加至 report
。
接着执行:
node report.js ./2021-09-25.json ./2021-09-26.json
成果就是你今天看到的「每日铁人赛热门 Top 10」啦!(但当然不包括我的评语)
以 9/25 20:00 ~ 9/26 20:00 文章观看数增加值排名
+468
Day 1 无限手套 AWS 版:掌控一切的 5 + 1 云端必学主题
+394
Day 3 云端四大平台比较:AWS . GCP . Azure . Alibaba
+387
Day 2 AWS 是什麽?又为何企业这麽需要 AWS 人才?
+365
Day 4 网路宝石:AWS VPC Region/AZ vs VPC/Subnet 关系介绍
+348
Day 5 网路宝石:AWS VPC 架构 Routes & Security (上)
+338
Day 15 储存宝石:S3 架构 & 版本控管 (Versioning)
+335
Day 9 运算宝石:EC2 重点架构
+334
Day 6 网路宝石:AWS VPC 架构 Routes & Security (下)
+330
Day 8 网路宝石:【Lab】VPC外网 Public Subnet to the Internet (IGW) (下)
+330
Day 16 储存宝石:S3 储存类别 & 生命周期管理
我开始觉得 AWS 系列已经逐渐让这个排行榜失去意义了...
>>: 【没钱买ps,PyQt自己写】Day 11 - 以 Qlabel 在 PyQt 中显示图片 (基於 QImage 使用 OpenCV)
比较运算子 >、<、>=、<=:分别为「大於」、「小於」、「大於等於」、「小...
一、总结 总结来说,今天研究了一整天论文, 该篇论文对蒐集5分线数据,并以此预测之後的股价倾向, 与...
用途: sender和receiver沟通机制,FIFO(先进先出)。 参考来源: 郝林-Go语言核...
建立HTML档案 打开VSCode > 档案 > 另存新档为html档+命名 > ...
上一篇把"Hello World!"更改成了了 但字体太小了,看不清楚到底打对还...