parent
b29ef8f941
commit
97c196e755
|
|
@ -386,13 +386,13 @@ RSSHub 提供下列 API 接口:
|
|||
|
||||
### 简书
|
||||
|
||||
<route name="首页" author="DIYgod" example="/jianshu/home" path="/jianshu/home"/>
|
||||
<route name="首页" author="DIYgod HenryQW" example="/jianshu/home" path="/jianshu/home"/>
|
||||
|
||||
<route name="热门" author="DIYgod HenryQW" example="/jianshu/trending/weekly" path="/jianshu/trending/:timeframe" :paramsDesc="['按周 `weekly` 或 按月 `monthly`']"/>
|
||||
|
||||
<route name="专题" author="DIYgod" example="/jianshu/collection/xYuZYD" path="/jianshu/collection/:id" :paramsDesc="['专题 id, 可在专题页 URL 中找到']"/>
|
||||
<route name="专题" author="DIYgod HenryQW" example="/jianshu/collection/xYuZYD" path="/jianshu/collection/:id" :paramsDesc="['专题 id, 可在专题页 URL 中找到']"/>
|
||||
|
||||
<route name="作者" author="DIYgod" example="/jianshu/user/yZq3ZV" path="/jianshu/user/:id" :paramsDesc="['作者 id, 可在作者主页 URL 中找到']"/>
|
||||
<route name="作者" author="DIYgod HenryQW" example="/jianshu/user/yZq3ZV" path="/jianshu/user/:id" :paramsDesc="['作者 id, 可在作者主页 URL 中找到']"/>
|
||||
|
||||
### 知乎
|
||||
|
||||
|
|
|
|||
|
|
@ -103,14 +103,82 @@ sidebar: auto
|
|||
|
||||
```js
|
||||
const $ = cheerio.load(data); // 使用 cheerio 加载返回的 HTML
|
||||
const list = $('.note-list li'); // 使用 cheerio 选择器,选择 class="note-list" 下的所有 <li> 元素,返回 cheerio node 对象数组
|
||||
const list = $('.note-list li').get();
|
||||
// 使用 cheerio 选择器,选择 class="note-list" 下的所有 <li> 元素,返回 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',
|
||||
// 选择 <meta name="description"> 的 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(),
|
||||
// 文章正文,对每一个 <li> DOM 进行操作,生成正文
|
||||
description: `作者:${item.find('.nickname').text()}<br>描述:${item.find('.abstract').text()}<br><img referrerpolicy="no-referrer" src="https:${item.find('.img-blur').data('echo')}">`,
|
||||
// 文章发布时间
|
||||
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,
|
||||
};
|
||||
|
||||
// 至此本路由结束
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()}<br>描述:${item.find('.abstract').text()}<br><img referrerpolicy="no-referrer" src="https:${item.find('.img-blur').data('echo')}">`,
|
||||
pubDate: new Date(item.find('.time').data('shared-at')).toUTCString(),
|
||||
link: `https://www.jianshu.com${item.find('.title').attr('href')}`,
|
||||
};
|
||||
})
|
||||
.get(),
|
||||
item: result,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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()}<br>描述:${item.find('.abstract').text()}<br><img referrerpolicy="no-referrer" src="https:${item.find('.img-blur').data('echo')}">`,
|
||||
pubDate: new Date(item.find('.time').data('shared-at')).toUTCString(),
|
||||
link: `https://www.jianshu.com${item.find('.title').attr('href')}`,
|
||||
};
|
||||
})
|
||||
.get(),
|
||||
item: result,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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()}<br>描述:${item.find('.abstract').text()}<br><img referrerpolicy="no-referrer" src="https:${item.find('.img-blur').data('echo')}">`,
|
||||
pubDate: new Date(item.find('.time').data('shared-at')).toUTCString(),
|
||||
link: `https://www.jianshu.com${item.find('.title').attr('href')}`,
|
||||
};
|
||||
})
|
||||
.get(),
|
||||
item: result,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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()}<br>描述:${item.find('.abstract').text()}<br><img referrerpolicy="no-referrer" src="https:${item.find('.img-blur').data('echo')}">`,
|
||||
pubDate: new Date(item.find('.time').data('shared-at')).toUTCString(),
|
||||
link: `https://www.jianshu.com${item.find('.title').attr('href')}`,
|
||||
};
|
||||
})
|
||||
.get(),
|
||||
item: result,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
Loading…
Reference in New Issue