diff --git a/docs/README.md b/docs/README.md
index 621ddaa1f..c341526a4 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -386,13 +386,13 @@ RSSHub 提供下列 API 接口:
### 简书
-
+
-
+
-
+
### 知乎
diff --git a/docs/joinus/README.md b/docs/joinus/README.md
index db05a0f40..e2d834e76 100644
--- a/docs/joinus/README.md
+++ b/docs/joinus/README.md
@@ -103,14 +103,82 @@ sidebar: auto
```js
const $ = cheerio.load(data); // 使用 cheerio 加载返回的 HTML
- const list = $('.note-list li'); // 使用 cheerio 选择器,选择 class="note-list" 下的所有
元素,返回 cheerio node 对象数组
+ const list = $('.note-list li').get();
+ // 使用 cheerio 选择器,选择 class="note-list" 下的所有 元素,返回 cheerio node 对象数组
+ // cheerio get() 方法将 cheerio node 对象数组转换为 node 对象数组
// 注:每一个 cheerio node 对应一个 HTML DOM
// 注:cheerio 选择器与 jquery 选择器几乎相同
// 参考 cheerio 文档:https://cheerio.js.org/
```
- 赋值给 `ctx.state.data`
+ 使用 /jianshu/utils.js 类进行全文获取:
+
+ ```js
+ const result = await util.ProcessFeed(list, ctx.cache);
+ ```
+
+ /jianshu/utils.js 类中的全文获取逻辑:
+
+ ```js
+ const requestList = [];
+
+ // 使用 Promise.all() 进行 async 并发
+ const result = await Promise.all(
+ // 遍历每一篇文章
+ list.map(async (item) => {
+ const $ = cheerio.load(item);
+
+ // 还原相对链接为绝对链接
+ const itemUrl = url.resolve(host, $('.title').attr('href'));
+
+ // 查询缓存
+ const cache = await caches.get(itemUrl);
+ if (cache) {
+ return Promise.resolve(JSON.parse(cache));
+ }
+
+ // 返回新的对象
+ const single = {
+ title: $('.title').text(),
+ link: itemUrl,
+ author: $('.nickname').text(),
+ guid: itemUrl,
+ };
+
+ // 创建新的 axios 请求,存入 requestList 备用
+ const es = axios.get(itemUrl);
+ requestList.push(es);
+ return Promise.resolve(single);
+ })
+ );
+
+ // 并发所有 axios 请求
+ const responses = await axios.all(requestList);
+
+ // 循环 axios 结果
+ for (let i = 0; i < responses.length; i++) {
+ const $ = cheerio.load(responses[i].data);
+
+ // 根据网站 HTML,适配相应 selectors
+ result[i].description = $('.show-content-free').html();
+ const date = new Date(
+ $('.publish-time')
+ .text()
+ .match(/\d{4}.\d{2}.\d{2} \d{2}:\d{2}/)
+ );
+
+ // 处理日期时区,东八区 GMT +8 即为 8
+ const timeZone = 8;
+ const serverOffset = date.getTimezoneOffset() / 60;
+ result[i].pubDate = new Date(date.getTime() - 60 * 60 * 1000 * (timeZone + serverOffset)).toUTCString();
+
+ // 存入缓存,缓存时间(单位:秒)设置为 1(小时) * 60(分钟) * 60(秒)= 3600(秒)
+ caches.set(result[i].link, JSON.stringify(result[i]), 1 * 60 * 60);
+ }
+ ```
+
+ 将结果 `result` 赋值给 `ctx.state.data`
```js
ctx.state.data = {
@@ -118,25 +186,7 @@ sidebar: auto
link: 'https://www.jianshu.com',
// 选择 的 content 属性
description: $('meta[name="description"]').attr('content'),
- item:
- list &&
- list
- .map((index, item) => {
- // 遍历 cheerio node 对象数组
- // 注意,此处采用的为 cheerio map() 方法与 node 内置 map() 不同
- item = $(item);
- return {
- // 文章标题
- title: item.find('.title').text(),
- // 文章正文,对每一个 DOM 进行操作,生成正文
- description: `作者:${item.find('.nickname').text()}
描述:${item.find('.abstract').text()}
`,
- // 文章发布时间
- pubDate: new Date(item.find('.time').data('shared-at')).toUTCString(),
- // 文章链接
- link: `https://www.jianshu.com${item.find('.title').attr('href')}`,
- };
- })
- .get(), // cheerio get() 方法将 cheerio node 对象数组转换为 node 对象数组
+ item: result,
};
// 至此本路由结束
diff --git a/routes/bilibili/userChannel.js b/routes/bilibili/userChannel.js
index 97d470bb3..5b250b679 100644
--- a/routes/bilibili/userChannel.js
+++ b/routes/bilibili/userChannel.js
@@ -7,7 +7,6 @@ module.exports = async (ctx) => {
const userName = await cache.getUsernameFromUID(ctx, uid);
const host = `https://api.bilibili.com/x/space/channel/video?mid=${uid}&cid=${cid}&pn=1&ps=10&order=0`;
-
const response = await axios({
method: 'get',
url: host,
diff --git a/routes/jianshu/collection.js b/routes/jianshu/collection.js
index 35419053e..31a7b1ba9 100644
--- a/routes/jianshu/collection.js
+++ b/routes/jianshu/collection.js
@@ -1,5 +1,6 @@
const axios = require('../../utils/axios');
const cheerio = require('cheerio');
+const util = require('./utils');
module.exports = async (ctx) => {
const id = ctx.params.id;
@@ -15,24 +16,14 @@ module.exports = async (ctx) => {
const data = response.data;
const $ = cheerio.load(data);
- const list = $('.note-list li');
+ const list = $('.note-list li').get();
+
+ const result = await util.ProcessFeed(list, ctx.cache);
ctx.state.data = {
title: $('title').text(),
link: `https://www.jianshu.com/c/${id}`,
description: $('meta[name="description"]').attr('content') || $('title').text(),
- item:
- list &&
- list
- .map((index, item) => {
- item = $(item);
- return {
- title: item.find('.title').text(),
- description: `作者:${item.find('.nickname').text()}
描述:${item.find('.abstract').text()}
`,
- pubDate: new Date(item.find('.time').data('shared-at')).toUTCString(),
- link: `https://www.jianshu.com${item.find('.title').attr('href')}`,
- };
- })
- .get(),
+ item: result,
};
};
diff --git a/routes/jianshu/home.js b/routes/jianshu/home.js
index 7a4417355..8c0efa72d 100644
--- a/routes/jianshu/home.js
+++ b/routes/jianshu/home.js
@@ -1,5 +1,6 @@
const axios = require('../../utils/axios');
const cheerio = require('cheerio');
+const util = require('./utils');
module.exports = async (ctx) => {
const response = await axios({
@@ -13,24 +14,14 @@ module.exports = async (ctx) => {
const data = response.data;
const $ = cheerio.load(data);
- const list = $('.note-list li');
+ const list = $('.note-list li').get();
+
+ const result = await util.ProcessFeed(list, ctx.cache);
ctx.state.data = {
title: '简书首页',
link: 'https://www.jianshu.com',
description: $('meta[name="description"]').attr('content'),
- item:
- list &&
- list
- .map((index, item) => {
- item = $(item);
- return {
- title: item.find('.title').text(),
- description: `作者:${item.find('.nickname').text()}
描述:${item.find('.abstract').text()}
`,
- pubDate: new Date(item.find('.time').data('shared-at')).toUTCString(),
- link: `https://www.jianshu.com${item.find('.title').attr('href')}`,
- };
- })
- .get(),
+ item: result,
};
};
diff --git a/routes/jianshu/trending.js b/routes/jianshu/trending.js
index b8cd7fd2c..4f8108aa6 100644
--- a/routes/jianshu/trending.js
+++ b/routes/jianshu/trending.js
@@ -1,9 +1,9 @@
const axios = require('../../utils/axios');
const cheerio = require('cheerio');
+const util = require('./utils');
module.exports = async (ctx) => {
const link = `https://www.jianshu.com/trending/${ctx.params.timeframe}`;
-
const response = await axios({
method: 'get',
url: link,
@@ -15,24 +15,14 @@ module.exports = async (ctx) => {
const data = response.data;
const $ = cheerio.load(data);
- const list = $('.note-list li');
+ const list = $('.note-list li').get();
+
+ const result = await util.ProcessFeed(list, ctx.cache);
ctx.state.data = {
title: `简书 ${ctx.params.timeframe === 'weekly' ? '7' : '30'} 日热门`,
link,
description: `简书 ${ctx.params.timeframe === 'weekly' ? '7' : '30'} 日热门`,
- item:
- list &&
- list
- .map((index, item) => {
- item = $(item);
- return {
- title: item.find('.title').text(),
- description: `作者:${item.find('.nickname').text()}
描述:${item.find('.abstract').text()}
`,
- pubDate: new Date(item.find('.time').data('shared-at')).toUTCString(),
- link: `https://www.jianshu.com${item.find('.title').attr('href')}`,
- };
- })
- .get(),
+ item: result,
};
};
diff --git a/routes/jianshu/user.js b/routes/jianshu/user.js
index ad5e947a1..f5132b48e 100644
--- a/routes/jianshu/user.js
+++ b/routes/jianshu/user.js
@@ -1,5 +1,6 @@
const axios = require('../../utils/axios');
const cheerio = require('cheerio');
+const util = require('./utils');
module.exports = async (ctx) => {
const id = ctx.params.id;
@@ -15,24 +16,14 @@ module.exports = async (ctx) => {
const data = response.data;
const $ = cheerio.load(data);
- const list = $('.note-list li');
+ const list = $('.note-list li').get();
+
+ const result = await util.ProcessFeed(list, ctx.cache);
ctx.state.data = {
title: $('title').text(),
link: `https://www.jianshu.com/u/${id}`,
description: $('meta[name="description"]').attr('content') || $('title').text(),
- item:
- list &&
- list
- .map((index, item) => {
- item = $(item);
- return {
- title: item.find('.title').text(),
- description: `作者:${item.find('.nickname').text()}
描述:${item.find('.abstract').text()}
`,
- pubDate: new Date(item.find('.time').data('shared-at')).toUTCString(),
- link: `https://www.jianshu.com${item.find('.title').attr('href')}`,
- };
- })
- .get(),
+ item: result,
};
};
diff --git a/routes/jianshu/utils.js b/routes/jianshu/utils.js
new file mode 100644
index 000000000..f49efbbf8
--- /dev/null
+++ b/routes/jianshu/utils.js
@@ -0,0 +1,57 @@
+const axios = require('../../utils/axios');
+const cheerio = require('cheerio');
+const url = require('url');
+
+const ProcessFeed = async (list, caches) => {
+ const host = 'https://www.jianshu.com';
+
+ const requestList = [];
+
+ const result = await Promise.all(
+ list.map(async (item) => {
+ const $ = cheerio.load(item);
+
+ const itemUrl = url.resolve(host, $('.title').attr('href'));
+
+ const cache = await caches.get(itemUrl);
+ if (cache) {
+ return Promise.resolve(JSON.parse(cache));
+ }
+ const single = {
+ title: $('.title').text(),
+ link: itemUrl,
+ author: $('.nickname').text(),
+ guid: itemUrl,
+ };
+
+ const es = axios.get(itemUrl);
+ requestList.push(es);
+ return Promise.resolve(single);
+ })
+ );
+
+ const responses = await axios.all(requestList);
+
+ for (let i = 0; i < responses.length; i++) {
+ const $ = cheerio.load(responses[i].data);
+
+ result[i].description = $('.show-content-free').html();
+
+ const date = new Date(
+ $('.publish-time')
+ .text()
+ .match(/\d{4}.\d{2}.\d{2} \d{2}:\d{2}/)
+ );
+
+ const timeZone = 8;
+ const serverOffset = date.getTimezoneOffset() / 60;
+ result[i].pubDate = new Date(date.getTime() - 60 * 60 * 1000 * (timeZone + serverOffset)).toUTCString();
+ caches.set(result[i].link, JSON.stringify(result[i]), 1 * 60 * 60);
+ }
+
+ return result;
+};
+
+module.exports = {
+ ProcessFeed,
+};