摘要:Deno 是一个 JavaScript/TypeScript 的运行时,默认使用安全环境执行代码,有着卓越的开发体验。

有人的地方就有江湖,有江湖的地方就有争论。前些天,继《[译]为什么如今 Deno 正全面取代 Node.js》之后,又有了《【译】Deno 已经死了吗?》,也许这便是江湖。说回标题”Deno 在手,天下我有“,其实 Deno 换成Charj、NodeJS、Java 等其他名词都一样,毕竟只是标题罢了,可能真正不一样的是使用她的愉悦感。对我而言,能给我带来 Copy 的快感,便是极好的!

源起

本周,被@justjavac 巨佬的各个热搜榜项目吸睛了,抱着对技术的三分钟热情以及对优秀代码的学习心切,我又开始了新的代码拷贝旅程。二话不说,先git clone一顿操作猛如虎,定睛一看,好像这几个项目的实现都差不多,也请教了巨佬本尊确定实现是一样的,但为毛要开 4 个 repo 呢?也许这就是单一职责原则吧。然后,我寻思着能不能整合一下再加点别的热搜榜就能变成trending in one,是不是很棒的想法,哈哈哈哈。接下来,我还会对今日头条下手--”得热搜者得天下,热搜榜拿来吧!“,三下除二拿到了头条热搜榜(尽管需要输入图片验证码)。最后就是资源整合,不过发现 README.md 爆了,看来单例还是有单例的好。

即刻获取今日热搜榜 ️ trending-in-one

剖析

关于如何实现热搜汇总,如果不看源码,我也只能想到调用相关热搜榜的接口来获取,可别人的接口又怎么会给你随意调用呢?通过拜读大佬的源码,我看到了通过正则匹配 DOM 节点获取对应的标题链接之类的,我看到了通过注释定位包裹的内容并进行替换,我看到了 JavaScript 如何处理重复的数据,我看到了如何借助 github action 实现 Deno 应用的构建……尽管只是一个微不足道的项目,却包罗万象,作者将各种技巧搭配自如、灵活运用,简直是出神入化、登峰造极啊(PS:在我看来事实如此)。

其实抛开语言和平台,要想实现热搜汇总榜,无非就是三步走:① 获取数据 ② 处理数据 ③ 输出数据。接下来从 Deno 的视角来详细解说这三步是如何走的:

获取数据

当我们遇到一个需求,可能要从它的本质出发,比如要实现热搜汇总,首先我们就需要各大平台的热搜数据,如今日头条热搜榜、知乎热门视频、知乎热门话题、知识热门搜索、微博热门搜索等等,怎么获取呢?常规的手段就是框按 F12 看看 Network,实在不行试试抓包工具.好在“前人栽树后人乘凉”,于是乎我们便有了各平台的接口,获取数据岂不是信手沾来。

头条热榜:https://is-lq.snssdk.com/api/suggest_words/?business_id=10016

微博热搜:https://s.weibo.com/top/summary

知乎热门话题:https://www.zhihu.com/api/v3/feed/topstory/hot-lists/total?limit=100

知乎热门视频:https://www.zhihu.com/api/v3/feed/topstory/hot-lists/zvideo?limit=100

知乎热搜: https://www.zhihu.com/api/v4/search/top_search

当然以上接口并非永久有效,目前来看也只能是能用多久用多久了,如果您不满足于此,亦可以试试Twitter、Medium 等等(PS:好人一生平安)。不过,上边的接口中,微博热搜特立独行,她返回的是 HTML 需要用到正则匹配即可拿到热搜标题和链接,正则可把我难住了:/<a href="(\/weibo\?q=[^"]+)".*?>(.+)<\/a>/g,似懂非懂。各位少侠可否移步评论区多多指教?

以今日头条为例,获取数据似乎显示特别简单,但扪心自问 await、fetch、TypeScript 我又了解多少呢?

const response = await fetch(
"https://is-lq.snssdk.com/api/suggest_words/?business_id=10016",
); if (!response.ok) {
console.error(response.statusText);
Deno.exit(-1);
} const result: ToutiaoTopSearch = await response.json();
const words = result.data[0].words;

处理数据

最终我们的数据可能是这样的--参见2020-12-01 头条热搜

细心的小伙伴也许看到了.md 文件中的注释,就是这注释起到了关键的作用,移花接木?为他人做嫁衣?在进行数据更新的时候,我们可以巧妙地利用注释作为参照,动态替换注释开头和注释结尾中间的内容,利用 Deno 标准库及一些内置 API 完成文件操作,比如今日头条热搜数据的创建及更新:

export function createTuotiaoList(words: ToutiaoWord[]): string {
return `<!-- BEGIN TOUTIAO -->
<!-- 最后更新时间 ${Date()} -->
${
words.map((x) => `1. [${x.word}](${x.url})`)
.join("\n")
}
<!-- END TOUTIAO -->`;
} export async function createReadme4Toutiao(
words: ToutiaoWord[],
): Promise<string> {
const readme = await Deno.readTextFile("./README.md");
return readme.replace(
/<!-- BEGIN TOUTIAO -->[\W\w]*<!-- END TOUTIAO -->/,
createTuotiaoList(words),
);
}

另外再对比新旧数据的时候,用到了常用的数组迭代方法及**Object.entries()** ,感觉 MDN 还得多刷,完全不熟练,尤其是串起来的时候:

/** 合并两次热搜并去重 */
export function mergeWords4Toutiao(
words: ToutiaoWord[],
another: ToutiaoWord[],
): ToutiaoWord[] {
const obj: Record<string, string> = {};
for (const w of words.concat(another)) {
obj[w.url] = w.word;
}
return Object.entries(obj).map(([url, word]) => ({
url,
word,
}));
}

输出数据

其实在处理数据的时候,我们基本完成了数据输出的准备工作,鉴于本项目中只输出为.md 文件和.json 文件,直接调用之前的处理数据方法即可,简单粗暴:

export async function toutiaoSearch() {
// 保存原始数据
await Deno.writeTextFile(fullPath, JSON.stringify(wordsAll)); // 更新 README.md
const readme = await createReadme4Toutiao(wordsAll);
await Deno.writeTextFile("./README.md", readme); // 更新 archives
const archiveText = createArchive4Toutiao(wordsAll, yyyyMMdd);
const archivePath = join("archives/toutiao-search", `${yyyyMMdd}.md`);
await Deno.writeTextFile(archivePath, archiveText);
}

如果不局限于输出数据为文件,我们可以实现的功能就可以多了,发送热搜数据(或者任何您能获取到的数据)到邮件、短信、钉钉机器人……不禁又想起了老湿常说的“带薪拉屎”必备,想想每天早上第一泡就能享用热乎的热搜榜,似乎有种“家事国事天下事,事事关心”的错觉,坐着点开一条条热搜表示“朕已阅”……

Github Action

如果说 Serverless 是个好东西,那么Github Action怎么逃得过真香定律呢?在 GitHub Actions 的仓库中自动化、自定义和执行软件开发工作流程。您可以发现、创建和共享操作以执行您喜欢的任何作业(包括 CI/CD),并将操作合并到完全自定义的工作流程中。通俗点就是您可以为所欲为,比如定时构建 Deno 应用。为了能够每小时更新我们的热搜汇总,我们需要给 github 仓库新增**.github/workflows** 文件夹,也就是前边所说的工作流 ,然后新建 ci.yml 和 schedule.yml 告诉 Github Action 应该如何做,这样她就是听话的贴心小秘书了,因为她会告诉您每一次执行工作流的详细结果,就算构建失败也有邮件温馨提醒。至于 yml 的内容应该写啥,请参照官方文档和 Deno 社区经典案例(PS:好像是我的知识盲区,用得还不熟练,怕带坑)。 当然,如果想直接开干的话,可以在仓库的 Action 选项卡中获取到 github 提供的温馨建议。少年,亮剑吧!

尾声

探索的脚步永不止步,不过于我,好像置身于小黑屋,无论我怎么走都无法走出去,十多年了,依旧原地踏步踏。小时候,梦想长大以后一家子各兄弟能大干一场实现家族企业的幻想却奈何爷辈早逝凝聚力尽失;到中学,怀恨于内心的脆弱被班主任拿捏死失去重点中学的入场券落为鸡头放弃自我;万幸有的大学读,却虚度光阴于网吧、操场、情人坡、后山,终费万事……到此刻及未来,终究要为过去的沉沦颓废而埋单。唉,年纪大了,还能怎么折腾?谨以此段,奉劝家中无矿、朝中无权的年轻人,莫虚度此生,至少 Deno 真香!

完整项目地址: https://github.com/hu-qi/trending-in-one

点击关注,第一时间了解华为云新鲜技术~

了不起的 Deno:带你极速获取各大平台今日热榜的更多相关文章

  1. 如何获取各大平台的播放地址(获得优酷的m3u8播放地址)为例

    1.打开safari 2.在顶部(黑色小苹果)旁边,点击safari. 3.打开里面的 偏好设置. 4.在高级 中 找到 “在菜单栏中显示开发菜单” 并打勾. 5.关闭窗口后,可以发现safari 顶 ...

  2. 爬虫神器XPath,程序员带你免费获取周星驰等明星热门电影

    本教程由"做全栈攻城狮"原创首发,本人大学生一枚平时还需要上课,但尽量每日更新文章教程.一方面把我所习得的知识分享出来,希望能对初学者有所帮助.另一方面总结自己所学,以备以后查看. ...

  3. 利用scrapy获取抽屉新热榜的标题和内容以及新闻地址保存到本地

    1.安装scrapy pip3 install scrapy 2.打开terminal,cd 到想要创建程序的目录下 3.创建一个scrapy项目 在终端输入:scrapy startproject ...

  4. IP达人启示录(学会经营自己:靠软件来扩大自己的IP,或者获取很大的名声)

    在家附近的一个小公园中,一个老人每天晚上都在用水练习书法,他的字写的的确很不错,不懂书法的我,看了就感觉非常的带劲--苍劲有力.今晚再次路过的时候,就有种想和这个老人聊一聊的冲动,那么多年纪了,用书法 ...

  5. Android获取OneNET云平台数据

    尝试HttpURLConnection "get"方式获取了www.baidu.com的数据后,试着获取OneNET云平台的设备数据(设备数据已成功上传至云平台) .java文件 ...

  6. 三篇文章带你极速入门php(三)之php原生实现登陆注册

    看下成果 ps:纯天然h5,绝不添加任何添加剂(css)以及化学成分(js)(<( ̄ ﹌  ̄)我就是喜欢纯天然,不接受任何反驳) 关于本文 用原生的php和html做了一个登陆注册,大概是可以窥 ...

  7. 使用katalon自带Spy功能获取/验证控件Selector、XPath

    背景 最近刚接手一个katalon编写的UI自动化项目,页面最近刚改版,已有用例很多查找元素失败.了解到katalon元素定位支持xpath,所以直接使用chrome开发者工具打开目标页面+获取xpa ...

  8. 三篇文章带你极速入门php(一)之语法

    本文适合阅读用户 有其他语言基础的童鞋 看完w3cschool语法教程来回顾一下的童鞋(传送门,想全面看一下php语法推荐这里) 毫无基础然而天资聪慧颇有慧根(不要左顾右看说的就是你,老夫这里有一本& ...

  9. window.location.search 为何在url 带# 号时获取不到 ?

    我们在获取url参数时,会常常用到截取参数 getUrlParam(name) { const reg = new RegExp('(^|&)' + name + '=([^&]*)( ...

随机推荐

  1. spark求相同key的最大值

    需求: 求相同key的最大值  [("a", 3),  ("a", 2),  ("a", 5),  ("b", 5),  ...

  2. Charles使用part3——安装证书&手机抓取https请求

    一.配置 Charles 根证书 1.进入 Charles->Help->SSL Proxying->Install Charles Root Certificate ,会打开证书, ...

  3. Parameter 'name' implicitly has an 'any' type.

    出现在vue3版本 找到tsconfig.json文件 增加"noImplicitAny":flase,或把"strict":true改成"stric ...

  4. 汉诺塔问题实验--一个简洁的JAVA程序

    思路: 这里使用递归法 n==1的时候,直接把它从x移到z位置即可. 如果是n层,我们首先把上面的n- 1层移到y位置,然后把最 下面的那个最大的盘子,移到z位置,然后把y上面放的上面n-1层移到z位 ...

  5. nginx vhost配置

    server { listen 80; server_name crsdemo.my; index index.html index.htm index.php default.html defaul ...

  6. Flink基础:实时处理管道与ETL

    ​ 往期推荐: Flink基础:入门介绍 Flink基础:DataStream API Flink深入浅出:资源管理 Flink深入浅出:部署模式 Flink深入浅出:内存模型 Flink深入浅出:J ...

  7. Oracle(第二天)

    一.外键(foreign key):constraint , refenerces 例如:sno number(7) constraint fk_sno references student(sno) ...

  8. 【JVM第三篇--运行时数据区】程序计数器、虚拟机栈、本地方法栈

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.运行时数据区 我们在编写Java程序时,使用JVM的流程主要如下所示: 虚拟机在 ...

  9. linux 中断softirq tasklet

    硬中断为什么不能休眠--- 中断线程以及软中断解决了什么问题---- 软中断cb函数是否允许相应本地中断,什么时候开启中断关闭中断---- 什么是软中断上下文------- 什么是tasklet 和软 ...

  10. linux中几个文本文件查看命令

    Linux中,常用的文本文件查看命令介绍如下: 1. cat 用法: cat [options] filename options: -A: 显示全部. -E: 在每一行的后面加上"$&qu ...