1.前言
放假回家开启了休闲模式,看到腾讯视频上了新的网剧《开端》,啪的一下我就点进去了,一口气追了八集相当过瘾。然后就陷入等更新的无聊和空虚之中。于是想先看看豆瓣的评分和评价,没想到竟然还没出评分。
莫名地有些在意豆瓣评分(我看好的剧,分数不可能低 :D),有事没事点进网站看看。于是就想着写个简单地脚本定时的查一下评分,评分出来之后通知我。既然是做前端的,就用前端的方式写几行代码,解决这个需求。大概是因为我太菜了,几经尝试,踩了数个坑终于弄出了比较靠谱的方案。
2.初次尝试
分析一下需求:一段代码 --> 《开端》评分除了之后,通过windows通知弹窗通知我。
拆分一下需求,分为以下三步走:
- 通过网络请求得到网剧评分
- 将得到的网剧评分等信息展示出来
- 定时查询展示评分
2.1 查评分
最开始想通过豆瓣网页前端源代码找找查影视剧评分的接口(官方接口当然是首选),翻了半天没找到接口,定睛一看,第一个请求就把这个网页发过来了。好家伙,感情是服务端渲染SSR啊,这就真没办法找到接口了。
得了,还是上网搜搜接口吧,豆瓣这么大个公司,不能连个接口都不提供吧。
没承想,这还就真没有官方接口,找了半天终于找个一个开源项目提供接口。通过下面的接口调用:
https://movie.querydata.org/api?id=35332289
其中的id是豆瓣id,每个电影的豆瓣网页都可以在网址上看到这个id。https://movie.douban.com/subject/35332289/
至于发网络请求,这本来就是心血来潮的草台班子,用原生js一切从简了,最方便的就是用fetch直接拉数据。 代码如下:
fetch('https://movie.querydata.org/api?id=35332289')
.then(response => response.json()) //response是fetch的一个对象,通过json方法拿数据
.then(data => console.log(data));
2.2 发通知
万恶的chorme弹窗,本来是把他关了的,但为了这次的需求,还是暂时打开吧。如何通过web向桌面window发出通知,参考(baipiao)了《H5 notification浏览器桌面通知》。大佬已经将发通知的方法抽象出来了。前人栽树,后人伐木,代码如下:
function notifyMe(title, options) {
// 先检查浏览器是否支持
if (!window.Notification) {
console.log("浏览器不支持通知");
} else {
// 检查用户曾经是否同意接受通知
if (Notification.permission === "granted") {
var notification = new Notification(title, options); // 显示通知
} else if (Notification.permission === "default") {
// 用户还未选择,可以询问用户是否同意发送通知
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
console.log("用户同意授权");
var notification = new Notification(title, options); // 显示通知
} else if (permission === "default") {
console.warn("用户关闭授权 未刷新页面之前 可以再次请求授权");
} else {
// denied
console.log("用户拒绝授权 不能显示通知");
}
});
} else {
// denied 用户拒绝
console.log("用户曾经拒绝显示通知");
}
}
}
通过以下语句调用:
var options = {
dir: "auto", // 文字方向
body: 豆瓣评分// 通知主体
requireInteraction: true, // 不自动关闭通知
// 通知图标
icon: "https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7b543cfe4fb0428e926dcd42f79bfeb6~tplv-k3u1fbpfcp-watermark.image?",
};
notifyMe("豆瓣评分", options);
2.3 定时器
把这些东西糅合一下,再加上定时器,解决了首次查询先弹一次窗的需求,在加上跨域问题(在他的域中调用,即 movie.querydata.org/api?id=3533… 这个网页的控制台中),毕竟不是官方接口每30秒只能调用一次,定时器间隔得大于30秒。综合以上种种,可得代码如下:
function notifyMe(title, options) {
// 先检查浏览器是否支持
if (!window.Notification) {
console.log("浏览器不支持通知");
} else {
// 检查用户曾经是否同意接受通知
if (Notification.permission === "granted") {
var notification = new Notification(title, options); // 显示通知
} else if (Notification.permission === "default") {
// 用户还未选择,可以询问用户是否同意发送通知
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
console.log("用户同意授权");
var notification = new Notification(title, options); // 显示通知
} else if (permission === "default") {
console.warn("用户关闭授权 未刷新页面之前 可以再次请求授权");
} else {
// denied
console.log("用户拒绝授权 不能显示通知");
}
});
} else {
// denied 用户拒绝
console.log("用户曾经拒绝显示通知");
}
}
}
function queryMovie(movieId) {
fetch("https://movie.querydata.org/api?id=" + movieId)
.then((response) => response.json())
.then((data) => {
var options = {
dir: "auto", // 文字方向
body: `${data.originalName}:${
data.doubanRating === "" ? "暂无评分" : data.doubanRating
}`, // 通知主体
requireInteraction: true, // 不自动关闭通知
// 通知图标
icon: "https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7b543cfe4fb0428e926dcd42f79bfeb6~tplv-k3u1fbpfcp-watermark.image?",
};
if (firstQuery || data.doubanRating !== lastStatus) {
lastStatus = data.doubanRating;
notifyMe(data.originalName + "豆瓣评分", options);
if (!firstQuery) {
clearInterval(LoopId);
} else {
firstQuery = !firstQuery;
}
} else {
console.log(
`评分未改变,仍${
data.doubanRating === "" ? "无评分" : "为" + data.doubanRating
}, 查询时间:${Date()}`
);
}
});
}
let lastStatus = "";
let firstQuery = true;
const LoopId = setInterval(() => {
queryMovie("35332289");
}, 1000 * 40);
3.二次迭代
万万没想到,免费的接口有使用限制,每天限次数,让我升级账户。
咱可不能惯着他,另谋它法吧。
久经搜索,仍然没有可以白嫖的接口,怒了。毁灭吧,直接解析html文件了,反正只是拿个评分而已。回到最初的起点,
用
fetch加resonpse.text()方法拿数据,用正则把内容解析出来。再加上发通知的相同代码:
function notifyMe(title, options) {
// 先检查浏览器是否支持
if (!window.Notification) {
console.log("浏览器不支持通知");
} else {
// 检查用户曾经是否同意接受通知
if (Notification.permission === "granted") {
var notification = new Notification(title, options); // 显示通知
} else if (Notification.permission === "default") {
// 用户还未选择,可以询问用户是否同意发送通知
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
console.log("用户同意授权");
var notification = new Notification(title, options); // 显示通知
} else if (permission === "default") {
console.warn("用户关闭授权 未刷新页面之前 可以再次请求授权");
} else {
// denied
console.log("用户拒绝授权 不能显示通知");
}
});
} else {
// denied 用户拒绝
console.log("用户曾经拒绝显示通知");
}
}
}
function queryMovie(movieId) {
fetch("https://movie.douban.com/subject/" + movieId)
.then((response) => response.text())
.then((data) => {
let reg = /<div class="rating_sum">\n(.*)\n(.*)<\/div>/gi;
let matchs = reg.exec(data);
if (matchs === null) {
reg =
/<strong class="ll rating_num" property="v:average">(.*)<\/strong>/gi;
matchs = reg.exec(data);
}
const doubanRating = matchs[1].trim();
const regForTitle = /<span property="v:itemreviewed">(.*)<\/span>/g;
const matchsForTitle = regForTitle.exec(data);
const title = matchsForTitle[1].trim();
var options = {
dir: "auto", // 文字方向
body: title + " : " + doubanRating, // 通知主体
requireInteraction: true, // 不自动关闭通知
// 通知图标
icon: "https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7b543cfe4fb0428e926dcd42f79bfeb6~tplv-k3u1fbpfcp-watermark.image?",
};
if (firstQuery || doubanRating !== lastStatus) {
lastStatus = doubanRating;
notifyMe("豆瓣评分", options);
if (!firstQuery) {
clearInterval(LoopId);
} else {
firstQuery = !firstQuery;
}
} else {
console.log(
`评分未改变,仍${
doubanRating === "暂无评分" ? "无评分" : "为" + doubanRating
}, 查询时间:${Date()}`
);
}
});
}
let lastStatus = "";
let firstQuery = true;
const LoopId = setInterval(() => {
queryMovie("35332289");
}, 1000 * 40);
然后跨域又寄了,解决办法相同,到他的域中去( movie.douban.com/ ),再在其控制台运行这些代码,一切终于正常了。
4.总结
- 找个接口都这么难,互联网越来越不开放了
- 跨域很烦人
- 强推《开端》