fix(route): change to use api get data and refactor to v2 (#11809)

* fix(route): change to use api get data and refactor to v2

* fix(route): remove unreachable condition

* refactor: change route path

feat!: remove `/open163/latest` since `https://c.open.163.com/open/getLatestMovies.do` is broken

* fix: radar

---------
This commit is contained in:
Fatpandac
2023-02-14 02:15:52 +08:00
committed by GitHub
parent df44e1380f
commit 8283cd260a
29 changed files with 372 additions and 396 deletions
-5
View File
@@ -166,11 +166,6 @@
'xiaomi.cn': { _name: '小米社区', www: [{ title: '圈子', docs: 'https://docs.rsshub.app/bbs.html#xiao-mi-she-qu', source: '/board/:boardId', target: '/mi/bbs/board/:boardId' }] },
'163.com': {
_name: '网易',
ds: [{ title: '大神', docs: 'https://docs.rsshub.app/game.html#wang-yi-da-shen', source: '/user/:id', target: '/netease/ds/:id' }],
open: [
{ title: '公开课 - 精品课程', docs: 'https://docs.rsshub.app/study.html#wang-yi-gong-kai-ke', source: '/', target: '/open163/vip' },
{ title: '公开课 - 最新课程', docs: 'https://docs.rsshub.app/study.html#wang-yi-gong-kai-ke', source: '/', target: '/open163/latest' },
],
music: [
{
title: '云音乐 - 用户歌单',
+1 -1
View File
@@ -759,7 +759,7 @@ Example`https://www.iyingdi.com/tz/people/55547` id 是 `55547`
### 用户发帖
<Route author="luyuhuang" example="/netease/ds/63dfbaf4117741daaf73404601165843" path="/netease/ds/:id" :paramsDesc="['用户ID']"/>
<Route author="luyuhuang" example="/163/ds/63dfbaf4117741daaf73404601165843" path="/163/ds/:id" :paramsDesc="['用户ID']"/>
## 小黑盒
+8 -8
View File
@@ -3792,7 +3792,7 @@ column 为 third 时可选的 category:
### 栏目
<Route author="nczitzk" example="/netease/exclusive/qsyk" path="/netease/exclusive/:id?" :paramsDesc="['栏目, 默认为首页']">
<Route author="nczitzk" example="/163/exclusive/qsyk" path="/163/exclusive/:id?" :paramsDesc="['栏目, 默认为首页']">
| 分类 | 编号 |
| ---- | ---- |
@@ -3819,7 +3819,7 @@ column 为 third 时可选的 category:
### 更新
<Route author="HendricksZheng" example="/netease/dy/W4983108759592548559" path="/netease/dy/:id" :paramsDesc="['网易号 ID', '见如下说明']">
<Route author="HendricksZheng" example="/163/dy/W4983108759592548559" path="/163/dy/:id" :paramsDesc="['网易号 ID', '见如下说明']">
1. 在[网易号搜索页面](https://dy.163.com/v2/media/tosearch.html) 搜索想要订阅的网易号。
2. 打开网易号的任意文章。
@@ -3827,9 +3827,9 @@ column 为 third 时可选的 category:
</Route>
## 网易号(通用)
### 网易号(通用)
<Route author="mjysci" example="/netease/dy2/T1555591616739" path="/netease/dy2/:id" :paramsDesc="['id,该网易号主页网址最后一项html的文件名']" anticrawler="1"/>
<Route author="mjysci" example="/163/dy2/T1555591616739" path="/163/dy2/:id" :paramsDesc="['id,该网易号主页网址最后一项html的文件名']" anticrawler="1"/>
优先使用方法一,若是网易号搜索页面搜不到的小众网易号(文章页面不含`data-wemediaid`)则可使用此法。
触发反爬会只抓取到标题,建议自建。
@@ -3844,7 +3844,7 @@ column 为 third 时可选的 category:
### 今日关注
<Route author="nczitzk" example="/netease/today" path="/netease/today/:need_content?" :paramsDesc="['需要获取全文,填写 true/yes 表示需要,默认需要']">
<Route author="nczitzk" example="/163/today" path="/163/today/:need_content?" :paramsDesc="['需要获取全文,填写 true/yes 表示需要,默认需要']">
::: tip 提示
@@ -3856,7 +3856,7 @@ column 为 third 时可选的 category:
### 排行榜
<Route author="nczitzk" example="/netease/news/rank/whole/click/day" path="/netease/news/rank/:category?/:type?/:time?" :paramsDesc="['新闻分类,参见下表,默认为“全站”','排行榜类型,“点击榜”对应`click`,“跟贴榜”对应`follow`,默认为“点击榜”','统计时间,“1小时”对应`hour`,“24小时”对应`day`,“本周”对应`week`,“本月”对应`month`,默认为“24小时”']">
<Route author="nczitzk" example="/163/news/rank/whole/click/day" path="/163/news/rank/:category?/:type?/:time?" :paramsDesc="['新闻分类,参见下表,默认为“全站”','排行榜类型,“点击榜”对应`click`,“跟贴榜”对应`follow`,默认为“点击榜”','统计时间,“1小时”对应`hour`,“24小时”对应`day`,“本周”对应`week`,“本月”对应`month`,默认为“24小时”']">
::: tip 提示
@@ -3878,7 +3878,7 @@ column 为 third 时可选的 category:
### 专栏
<Route author="Solist-X" example="/netease/news/special/1" path="/netease/news/special/:type?" :paramsDesc="['栏目']">
<Route author="Solist-X" example="/163/news/special/1" path="/163/news/special/:type?" :paramsDesc="['栏目']">
| 轻松一刻 | 槽值 | 人间 | 大国小民 | 三三有梗 | 数读 | 看客 | 下划线 | 谈心社 | 哒哒 | 胖编怪聊 | 曲一刀 | 今日之声 | 浪潮 | 沸点 |
| ---- | -- | -- | ---- | ---- | -- | -- | --- | --- | -- | ---- | --- | ---- | -- | -- |
@@ -3888,7 +3888,7 @@ column 为 third 时可选的 category:
### 人间
<Route author="nczitzk" example="/netease/renjian/texie" path="/netease/renjian/:category?" :paramsDesc="['分类,见下表,默认为特写']">
<Route author="nczitzk" example="/163/renjian/texie" path="/163/renjian/:category?" :paramsDesc="['分类,见下表,默认为特写']">
| 特写 | 记事 | 大写 | 好读 | 看客 |
| ----- | ----- | ----- | ----- | ----- |
-4
View File
@@ -472,10 +472,6 @@ path="/ctfhub/upcoming/:limit?"
<Route author="hoilc" example="/open163/vip" path="/open163/vip" radar="1" rssbud="1"/>
### 最新课程
<Route author="hoilc" example="/open163/latest" path="/open163/latest" radar="1" rssbud="1"/>
## 下厨房
### 用户作品
-22
View File
@@ -397,28 +397,6 @@ module.exports = {
},
'163.com': {
_name: '网易',
ds: [
{
title: '大神',
docs: 'https://docs.rsshub.app/game.html#wang-yi-da-shen',
source: '/user/:id',
target: '/netease/ds/:id',
},
],
open: [
{
title: '公开课 - 精品课程',
docs: 'https://docs.rsshub.app/study.html#wang-yi-gong-kai-ke',
source: '/',
target: '/open163/vip',
},
{
title: '公开课 - 最新课程',
docs: 'https://docs.rsshub.app/study.html#wang-yi-gong-kai-ke',
source: '/',
target: '/open163/latest',
},
],
music: [
{
title: '云音乐 - 用户歌单',
+6 -6
View File
@@ -2894,18 +2894,18 @@ router.get('/futunn/highlights', lazyloadRouteHandler('./routes/futunn/highlight
// 网易新闻
// router.get('/netease/news/rank/:category?/:type?/:time?', lazyloadRouteHandler('./routes/netease/news/rank'));
router.get('/netease/news/special/:type?', lazyloadRouteHandler('./routes/netease/news/special'));
// router.get('/netease/news/special/:type?', lazyloadRouteHandler('./routes/netease/news/special'));
// 网易 - 网易号
router.get('/netease/dy/:id', lazyloadRouteHandler('./routes/netease/dy'));
router.get('/netease/dy2/:id', lazyloadRouteHandler('./routes/netease/dy2'));
// router.get('/netease/dy/:id', lazyloadRouteHandler('./routes/netease/dy'));
// router.get('/netease/dy2/:id', lazyloadRouteHandler('./routes/netease/dy2'));
// 网易大神
router.get('/netease/ds/:id', lazyloadRouteHandler('./routes/netease/ds'));
// router.get('/netease/ds/:id', lazyloadRouteHandler('./routes/netease/ds'));
// 网易公开课
router.get('/open163/vip', lazyloadRouteHandler('./routes/netease/open/vip'));
router.get('/open163/latest', lazyloadRouteHandler('./routes/netease/open/latest'));
// router.get('/open163/vip', lazyloadRouteHandler('./routes/netease/open/vip'));
// router.get('/open163/latest', lazyloadRouteHandler('./routes/netease/open/latest'));
// Boston.com
router.get('/boston/:tag?', lazyloadRouteHandler('./routes/boston/index'));
-41
View File
@@ -1,41 +0,0 @@
const url = require('url');
const got = require('@/utils/got');
const cheerio = require('cheerio');
const date = require('@/utils/date');
const root_url = 'https://ds.163.com/';
module.exports = async (ctx) => {
const id = ctx.params.id;
if (!id) {
throw Error('Bad parameter. See <a href="https://docs.rsshub.app/game.html#wang-yi-da-shen">https://docs.rsshub.app/game.html#wang-yi-da-shen</a>');
}
const current_url = url.resolve(root_url, '/user/' + id);
const response = await got({
method: 'get',
url: current_url,
});
const $ = cheerio.load(response.data);
const list = $('main.user-page__main div.feed-card')
.map((_, item) => {
item = $(item);
const a = item.find('a.feed-card__link-hide');
const desc = item.find('div.feed-card__body');
const title = desc.find('div.feed-text').text();
return {
title,
link: a.attr('href'),
description: desc.html(),
pubDate: date(item.find('time.userbar__time').text().trim()),
};
})
.get();
ctx.state.data = {
title: $('title').text(),
link: current_url,
item: list,
};
};
-54
View File
@@ -1,54 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const date = require('@/utils/date');
const iconv = require('iconv-lite');
module.exports = async (ctx) => {
const { id } = ctx.params;
const response = await got.get(`http://dy.163.com/v2/article/list.do?pageNo=1&wemediaId=${id}&size=10`);
const charset = response.headers['content-type'].split('=')[1];
const list = response.data.data.list;
let author, link;
const items = await Promise.all(
list.map(async (e) => {
if (e.docid) {
e.link = 'http://dy.163.com/v2/article/detail/' + e.docid + '.html';
}
author = e.source ? e.source : '';
const html = await ctx.cache.tryGet(e.link, async () =>
iconv.decode(
(
await got.get(e.link, {
responseType: 'buffer',
})
).data,
charset
)
);
const $ = cheerio.load(html, { decodeEntities: false });
const article = $('.post_body');
const single = {
title: e.title,
link: e.link,
description: article.html(),
pubDate: date(e.ptime, 8),
author: e.source,
};
return Promise.resolve(single);
})
);
ctx.state.data = {
title: `网易号 - ${author}`,
link,
description: '',
item: items,
};
};
-62
View File
@@ -1,62 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const { id } = ctx.params;
const limit = ctx.query.limit || 5;
const url = `https://www.163.com/dy/media/${id}.html`;
const response = await got(url, { responseType: 'buffer' });
const charset = response.headers['content-type'].split('=')[1];
const data = iconv.decode(response.data, charset);
const $ = cheerio.load(data, { decodeEntities: false });
const list = $('.media_articles ul li')
.slice(0, limit)
.map((_, item) => {
item = $(item);
const a = item.find('h2.media_article_title a');
return {
title: a.text(),
link: a.attr('href'),
pubDate: parseDate(item.find('.media_article_date').text()),
};
})
.get();
const items = await Promise.all(
list.map(async (item) => {
const itemData = await ctx.cache.tryGet(item.link, () =>
got(item.link, {
responseType: 'buffer',
}).then((it) => it.data)
);
const content = cheerio.load(itemData, { decodeEntities: false });
const postBody = content('.post_body');
postBody.find('p, br, section').each((_, elem) => elem.attribs && Object.keys(elem.attribs).forEach((attr) => content(elem).removeAttr(attr)));
postBody
.parent()
.find('*')
.contents()
.filter((_, elem) => elem.type === 'comment')
.remove();
return {
title: item.title,
link: item.link,
description: postBody.html(),
pubDate: item.pubDate,
};
})
);
ctx.state.data = {
title: $('.media_info h1').text(),
link: url,
description: $('.media_degist').text(),
item: items,
author: $('.media_name').text(),
};
};
-68
View File
@@ -1,68 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const list_response = await got.get('https://c.open.163.com/open/getLatestMovies.do?callback=');
const list = JSON.parse(list_response.data.match(/\((.*?)\)/)[1]) || [];
const parseContent = (htmlString) => {
const $ = cheerio.load(htmlString);
const author = $('.m-courseinfo__side ul > li:nth-child(2)');
const images = $('img');
for (let k = 0; k < images.length; k++) {
const testRealURL = $(images[k])
.attr('src')
.match(/\?url=([^&]+)/);
if (testRealURL) {
$(images[k]).replaceWith(`<img src="${testRealURL[1]}" />`);
}
}
const content = $('.m-courseinfo__side');
$('.i-container__title').remove();
return {
author: author.text().trim(),
description: content.html(),
pubDate: new Date(),
};
};
const out = await Promise.all(
list.map(async (item) => {
const link = item.url;
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const rssitem = {
title: item.title,
link,
};
try {
const response = await got.get(link);
const result = parseContent(response.data);
rssitem.author = result.author;
rssitem.description = result.description;
rssitem.pubDate = result.pubDate;
} catch (err) {
return Promise.resolve('');
}
ctx.cache.set(link, JSON.stringify(rssitem));
return Promise.resolve(rssitem);
})
);
ctx.state.data = {
title: '网易公开课 - 最新课程',
link: 'https://open.163.com/',
item: out.filter((item) => item !== ''),
};
};
-39
View File
@@ -1,39 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const url = 'https://vip.open.163.com';
const list_response = await got.get(url);
const $ = cheerio.load(list_response.data);
const list = $('.CourseListItem_ListItem')
.map((index, ele) => {
$('.CourseListItem_oriPrice', ele).remove();
const price = $('.CourseListItem_price', ele).text().trim();
return {
title: price + ' - ' + $('.CourseListItem_title', ele).text(),
link: url + $(ele).attr('href'),
};
})
.get();
const item = await Promise.all(
list.slice(0, 10).map((item) =>
ctx.cache.tryGet(item.link, async () => {
const res = await got.get(item.link);
const s = cheerio.load(res.data);
s('img').css('max-width', '100%');
const toc = s('.CourseCommonDetail_contentItem').eq(1).html();
item.description = `<div style="text-align: center;">${toc}` + s('.CourseCommonDetail_contentItem').first().html() + `</div>`;
return item;
})
)
);
ctx.state.data = {
title: '网易公开课 - 精品课程',
link: url,
item,
};
};
+33
View File
@@ -0,0 +1,33 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const { art } = require('@/utils/render');
const path = require('path');
const root_url = 'https://inf.ds.163.com';
module.exports = async (ctx) => {
const id = ctx.params.id;
const current_url = `${root_url}/v1/web/feed/basic/getSomeOneFeeds?feedTypes=1,2,3,4,6,7,10,11&someOneUid=${id}`;
const response = await got({
method: 'get',
url: current_url,
});
const data = response.data.result.feeds;
const list = data.map((feed) => ({
title: JSON.parse(feed.content).body.text,
link: `https://ds.163.com/feed/${feed.id}`,
description: art(path.resolve(__dirname, 'templates/ds.art'), {
text: JSON.parse(feed.content).body.text,
medias: JSON.parse(feed.content).body.media,
}),
pubDate: parseDate(feed.updateTime),
}));
ctx.state.data = {
title: `${response.data.result.userInfos[0].user.nick} 的动态`,
link: `https://ds.163.com/user/${id}`,
item: list,
};
};
+29
View File
@@ -0,0 +1,29 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
const { parseDyArticle } = require('./utils');
module.exports = async (ctx) => {
const { id } = ctx.params;
const response = await got(`https://dy.163.com/v2/article/list.do?pageNo=1&wemediaId=${id}&size=10`);
const charset = response.headers['content-type'].split('=')[1];
const list = response.data.data.list.map((e) => ({
title: e.title,
link: 'https://www.163.com/dy/article/' + e.docid + '.html',
pubDate: timezone(parseDate(e.ptime), 8),
author: e.source,
imgsrc: e.imgsrc,
}));
const items = await Promise.all(list.map((e) => parseDyArticle(charset, e, ctx.cache.tryGet)));
ctx.state.data = {
title: `网易号 - ${list[0].author}`,
link: items[0].feedLink,
description: items[0].feedDescription,
image: items[0].feedImage,
item: items,
};
};
+42
View File
@@ -0,0 +1,42 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
const { parseDyArticle } = require('./utils');
module.exports = async (ctx) => {
const { id } = ctx.params;
const limit = ctx.query.limit ?? 30;
const url = `https://www.163.com/dy/media/${id}.html`;
const response = await got(url, { responseType: 'buffer' });
const charset = response.headers['content-type'].split('=')[1];
const data = iconv.decode(response.data, charset);
const $ = cheerio.load(data);
const list = $('.tab_content ul li')
.slice(0, limit)
.toArray()
.map((item) => {
item = $(item);
return {
title: item.find('h4 a').text(),
link: item.find('a').first().attr('href'),
pubDate: timezone(parseDate(item.find('.time').text()), 8),
imgsrc: item.find('a img').attr('src'),
};
});
const items = await Promise.all(list.map((item) => parseDyArticle(charset, item, ctx.cache.tryGet)));
ctx.state.data = {
title: `${$('head title').text()} - 网易号`,
link: url,
description: $('.icon_line.desc').text(),
image: $('.head_img').attr('src'),
item: items,
author: $('h2').text(),
};
};
@@ -1,6 +1,11 @@
module.exports = {
'/exclusive/:id?': ['nczitzk'],
'/ds/:id': ['luyuhuang'],
'/dy/:id': ['HendricksZheng'],
'/dy2/:id': ['mjysci'],
'/news/rank/:category?/:type?/:time?': ['nczitzk'],
'/news/special/:type?': ['nczitzk'],
'/open/vip': ['hoilc'],
'/renjian/:category?': ['nczitzk'],
'/today/:need_content?': ['nczitzk'],
'/news/rank/:category?/:type?/:time?': ['nczitzk'],
};
@@ -3,7 +3,7 @@ const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const { parseDate } = require('@/utils/parse-date');
const rootUrl = 'http://news.163.com';
const rootUrl = 'https://news.163.com';
const config = {
whole: {
@@ -23,7 +23,7 @@ const config = {
title: '体育',
},
money: {
link: 'http://money.163.com/special/002526BH/rank.html',
link: 'https://money.163.com/special/002526BH/rank.html',
title: '财经',
},
tech: {
@@ -99,21 +99,27 @@ module.exports = async (ctx) => {
const list = $('div.tabContents')
.eq(timeRange[time].index + (category === 'whole' ? (type === 'click' ? -1 : 2) : type === 'click' ? 0 : 2))
.find('table tbody tr td a')
.map((_, item) => {
.toArray()
.map((item) => {
item = $(item);
return {
link: item.attr('href'),
};
})
.get();
});
const items = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
try {
const category = item.link.split('.163.com')[0].split('//').pop().split('.').pop();
const link = `https://3g.163.com/${category}/article/${item.link.split('/').pop()}`;
let link;
if (category === 'auto' || category === 'house' || category === 'travel') {
const category = item.link.split('.163.com')[0].split('//').pop().split('.').pop();
link = `https://3g.163.com/${category}/article/${item.link.split('/').pop()}`;
} else {
const pathname = new URL(item.link).pathname;
link = `https://3g.163.com${pathname}`;
}
const detailResponse = await got({
method: 'get',
@@ -121,16 +127,19 @@ module.exports = async (ctx) => {
});
const content = cheerio.load(detailResponse.data);
content('.bot_word').remove();
content('.bot_word, .js-open-app, .s-img').remove();
content('video').each(function () {
content(this).attr('src', content(this).attr('data-src'));
});
content('.article-body .image-lazy').each((_, elem) => {
elem.attribs.src = elem.attribs['data-src'] ? elem.attribs['data-src'] : elem.attribs.src;
});
item.title = content('meta[property="og:title"]').attr('content').replace('_手机网易网', '');
item.pubDate = parseDate(content('meta[property="og:release_date"]').attr('content'));
item.description = content('.content').html();
item.description = content('.article-body').html();
} catch (err) {
return Promise.resolve('');
return '';
}
return item;
@@ -138,17 +147,9 @@ module.exports = async (ctx) => {
)
);
for (let i = 0; i < items.length; i++) {
if (items[i] === undefined) {
items.splice(i, 1);
} else if (items[i].title === undefined) {
items.splice(i, 1);
}
}
ctx.state.data = {
title: `网易新闻${timeRange[time].title}${type === 'click' ? '点击' : '跟帖'}榜 - ${cfg.title}`,
link: currentUrl,
item: items,
item: items.filter((item) => item),
};
};
@@ -1,5 +1,5 @@
const got = require('@/utils/got');
const date = require('@/utils/date');
const { parseDate } = require('@/utils/parse-date');
const cheerio = require('cheerio');
const typeMap = {
1: '轻松一刻',
@@ -73,8 +73,8 @@ module.exports = async (ctx) => {
default:
break;
}
const url = `https://3g.163.com/touch/reconstruct/article/list/${type}/0-10.html`;
const response = await got.get(url);
const url = `https://3g.163.com/touch/reconstruct/article/list/${type}/0-20.html`;
const response = await got(url);
const data = response.data;
const matches = data.replace(/\s/g, '').match(/artiList\((.*?)\]\}\)/);
const articlelist0 = matches[1].replace(/".*?wangning/, '"articles') + ']}';
@@ -82,11 +82,8 @@ module.exports = async (ctx) => {
const articles = articlelist.articles;
const items = await Promise.all(
articles.map(async (article) => {
const title = article.title;
articles.map((article) => {
let url = article.url;
const time0 = article.ptime;
const time = time0.slice(0, 10) + ' ' + time0.slice(10);
if (url === null || article.skipType === 'video') {
const skipurl = article.skipURL;
const vid = skipurl.match(/vid=(.*?)$/);
@@ -94,20 +91,16 @@ module.exports = async (ctx) => {
url = `https://3g.163.com/exclusive/video/${vid[1]}.html`;
}
}
const content = await ctx.cache.tryGet(url, async () => {
const article_response = await got.get(url);
return ctx.cache.tryGet(url, async () => {
const article_response = await got(url);
const $ = cheerio.load(article_response.data);
return $('div[class="content"]').html() ? $('div[class="content"]').html() : $('div[class="video"]').html();
});
article.link = url;
article.description = $('.article-body').html() ? $('.article-body').html() : $('div[class="video"]').html();
article.pubDate = parseDate(article.ptime);
const list = {
title,
link: url,
description: content,
pubDate: date(time),
};
return Promise.resolve(list);
return article;
});
})
);
+63
View File
@@ -0,0 +1,63 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const { art } = require('@/utils/render');
const path = require('path');
module.exports = async (ctx) => {
const url = 'https://vip.open.163.com';
const list_response = await got(url);
const $ = cheerio.load(list_response.data);
const initialState = JSON.parse(
$('script')
.text()
.match(/window\.__INITIAL_STATE__=(.*);\(function\(\)\{var/)[1]
);
const list = Object.values(initialState.courseindex.myModules).flatMap((mod) =>
mod.contents.map((item) => ({
title: `${item.title} - ${item.subtitle}`,
author: item.authorName,
pubDate: parseDate(item.publishTime, 'x'),
link: `${url}/courses/${item.courseUid}/`,
courseUid: item.courseUid,
category: mod.name,
}))
);
const items = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const {
data: { data },
} = await got.post(`${url}/open/trade/pc/course/getCourseInfo.do`, {
form: {
courseUid: item.courseUid,
version: 1,
},
});
const $ = cheerio.load(data.courseInfo.description, null, false);
$('img').each((_, img) => {
img.attribs.src = img.attribs.src.split('?')[0];
delete img.attribs.width;
});
item.category = [item.category, data.courseInfo.firstClassifyName, data.courseInfo.secondClassifyName];
item.description = art(path.join(__dirname, '../templates/open.art'), {
data,
description: $.html(),
});
return item;
})
)
);
ctx.state.data = {
title: '网易公开课 - 精品课程',
link: url,
item: items,
};
};
+69
View File
@@ -0,0 +1,69 @@
const dy2 = {
title: '网易号(通用)',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-hao',
source: ['/dy/media/:id', '/news/sub/:id'],
target: (params) => `/163/dy2/${params.id.replace('.html', '')}`,
};
module.exports = {
'163.com': {
_name: '网易',
'.': [dy2],
'3g': [
dy2,
{
title: '独家栏目',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-du-jia-lan-mu',
source: ['/touch/exclusive/sub/:id'],
target: '/163/exclusive/:id?',
},
],
'c.m': [dy2],
ds: [
{
title: '大神',
docs: 'https://docs.rsshub.app/game.html#wang-yi-da-shen',
source: '/user/:id',
target: '/163/ds/:id',
},
],
m: [
{
title: '今日关注',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-xin-wen-jin-ri-guan-zhu',
source: ['/'],
target: '/163/today',
},
],
news: [
{
title: '排行榜',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-xin-wen-pai-hang-bang',
},
],
renjian: [
{
title: '人间',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-xin-wen-ren-jian',
source: ['/:category', '/'],
target: '/163/renjian/:category?',
},
],
'vip.open': [
{
title: '公开课 精品课程',
docs: 'https://docs.rsshub.app/study.html#wang-yi-gong-kai-ke',
source: ['/'],
target: '/163/open/vip',
},
],
'wp.m': [
{
title: '今日关注',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-xin-wen',
source: ['/163/html/newsapp/todayFocus/index.html', '/'],
target: '/163/today',
},
],
},
};
@@ -2,6 +2,7 @@ const got = require('@/utils/got');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
const titles = {
texie: '特写',
@@ -14,8 +15,8 @@ const titles = {
module.exports = async (ctx) => {
const category = ctx.params.category ?? 'texie';
const rootUrl = 'http://renjian.163.com';
const currentUrl = `${rootUrl}/special/renjian_${category}`;
const rootUrl = 'https://renjian.163.com';
const currentUrl = `${rootUrl}/special/renjian_${category}/`;
const response = await got({
method: 'get',
@@ -30,21 +31,21 @@ module.exports = async (ctx) => {
const urls = data.match(/url:"(.*)",/g);
if (urls) {
items = urls.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 15).map((item) => ({
items = urls.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 50).map((item) => ({
link: item.match(/url:"(.*)",/)[1],
}));
} else {
const $ = cheerio.load(data);
items = $('.article h3 a')
.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 15)
.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 50)
.toArray()
.map((_, item) => {
item = $(item);
return {
link: item.attr('href'),
};
})
.get();
});
}
items = await Promise.all(
@@ -57,9 +58,11 @@ module.exports = async (ctx) => {
const content = cheerio.load(detailResponse.data);
item.title = content('h1').text();
item.author = content('.author_txt name').text();
item.author = content('script')
.text()
.match(/renjian_author = '(.*)'/)[1];
item.description = content('#endText').html() ?? content('#content').html();
item.pubDate = parseDate(content('.pub_time').text() ?? content('.post_info').text().split('来源:')[0].trim());
item.pubDate = timezone(parseDate(content('.pub_time').text() ?? content('.post_info').text().split('来源:')[0].trim()), 8);
return item;
})
@@ -1,6 +1,11 @@
module.exports = function (router) {
router.get('/exclusive/:id?', require('./exclusive'));
router.get('/ds/:id', require('./ds'));
router.get('/dy/:id', require('./dy'));
router.get('/dy2/:id', require('./dy2'));
router.get('/news/rank/:category?/:type?/:time?', require('./news/rank'));
router.get('/news/special/:type?', require('./news/special'));
router.get('/open/vip', require('./open/vip'));
router.get('/renjian/:category?', require('./renjian'));
router.get('/today/:need_content?', require('./today'));
router.get('/news/rank/:category?/:type?/:time?', require('./rank'));
};
+7
View File
@@ -0,0 +1,7 @@
{{ text }}
{{ each medias }}
{{ if $value.mimeType.indexOf('image') > -1 }}
<img src="{{$value.url}}">
{{ /if }}
{{ /each }}
+6
View File
@@ -0,0 +1,6 @@
{{ if imgsrc }}
<img src="{{ imgsrc }}"><br>
{{ /if }}
{{ if postBody }}
{{@ postBody }}
{{ /if }}
+12
View File
@@ -0,0 +1,12 @@
{{ set chapterList = data.movieChapterList.length ? data.movieChapterList : data.audioChapterList; }}
{{ if chapterList }}
<div class="toc">
{{ each chapterList chapter chapterIndex }}
<h3>第{{ chapterIndex + 1 }}章 {{ chapter.title }}</h3>
{{ each chapter.contentList content contentIndex }}
<h4>{{ contentIndex + 1 }} {{ content.title }}</h4>
{{ /each }}
{{ /each }}
</div>
{{ /if }}
{{@ description }}
@@ -35,8 +35,8 @@ module.exports = async (ctx) => {
content('.bot_word').remove();
content('figure[data-echo]').each(function () {
content(this).html(`<img src="${content(this).attr('data-echo')}">`);
content('img').each((_, img) => {
img.attribs.src = img.attribs['data-src'] ? img.attribs['data-src'] : img.attribs.src;
});
item.description = content('.content, article').html();
+40
View File
@@ -0,0 +1,40 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');
const { art } = require('@/utils/render');
const path = require('path');
const parseDyArticle = (charset, item, tryGet) =>
tryGet(item.link, async () => {
const response = await got(item.link, {
responseType: 'buffer',
});
const html = iconv.decode(response.data, charset);
const $ = cheerio.load(html);
$('.post_main img').each((_, i) => {
if (!i.attribs.src) {
return;
}
const url = new URL(i.attribs.src);
if (url.host === 'nimg.ws.126.net') {
i.attribs.src = url.searchParams.get('url');
}
});
item.description = art(path.join(__dirname, 'templates/dy.art'), {
imgsrc: item.imgsrc?.split('?')[0],
postBody: $('.post_body').html(),
});
item.feedLink = $('.post_wemedia_name a').attr('href');
item.feedDescription = $('.post_wemedia_title').text();
item.feedImage = $('.post_wemedia_avatar img').attr('src');
return item;
});
module.exports = {
parseDyArticle,
};
-37
View File
@@ -1,37 +0,0 @@
module.exports = {
'163.com': {
_name: '网易',
'': [
{
title: '独家栏目',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-du-jia-lan-mu',
source: ['/'],
target: '/netease/exclusive/:id?',
},
],
renjian: [
{
title: '人间',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-xin-wen-ren-jian',
source: ['/:category', '/'],
target: '/netease/renjian/:category?',
},
],
news: [
{
title: '排行榜',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-xin-wen-pai-hang-bang',
source: ['/:category', '/'],
target: '/netease/news/rank/:category?/:type?/:time?',
},
],
m: [
{
title: '今日关注',
docs: 'https://docs.rsshub.app/new-media.html#wang-yi-xin-wen-jin-ri-guan-zhu',
source: ['/'],
target: '/netease/today/:need_content?',
},
],
},
};