fix(route): shu 上海大学 (#12803)

* fix(route): shu 上海大学

* Optimize code and update documentation

- shu/index.js & shu/jwc.js
    - use @/utils/parse-date to parse date
    - change "item.description" from text to HTML
    - change "url.resolve" (deprecated) to "new URL"
    - change the way of mapping "ctx.params.type" to link
        - now it accepts more route types
- university.md
    - update doc for new types
- router.js
    - add an alias because the website changed its host

* Update lib/routes/universities/shu/index.js

* Update lib/routes/universities/shu/jwc.js

* Update docs/university.md

* refactor: migrate to v2

---------
This commit is contained in:
东风有意 2023-07-18 21:29:18 +08:00 committed by GitHub
parent a5ddccc5ae
commit c41d23d043
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 135 additions and 148 deletions

View File

@ -2478,23 +2478,23 @@ jsjxy.hbut.edu.cn 证书链不全,自建 RSSHub 可设置环境变量 NODE_TLS
## 上海大学
### 上海大学官网信息
### 官网信息
<Route author="lonelyion" example="/shu/news" path="/shu/:type?" :paramsDesc="['消息类型,默认为`news`']">
| 综合新闻 | 科研动态 | 通知公告 |
| -------- | -------- | -------- |
| news | research | notice |
| 综合新闻 | 科研动态 | 通知公告 | 重要新闻 |
| -------- | -------- | -------- | --------- |
| news | research | notice | important |
</Route>
### 上海大学教务处通知公告
### 教务处通知公告
<Route author="tuxinghuan" example="/shu/jwc/notice" path="/shu/jwc/:type?" :paramsDesc="['消息类型,默认为`notice`']">
<Route author="tuxinghuan" example="/shu/jwb/notice" path="/shu/jwb/:type?" :paramsDesc="['消息类型,默认为`notice`']">
| 通知通告 | 新闻 |
| -------- | ---- |
| notice | news |
| 通知通告 | 新闻 | 政策文件 |
| -------- | ---- | -------- |
| notice | news | policy |
</Route>

View File

@ -744,8 +744,9 @@ router.get('/zjut/:type', lazyloadRouteHandler('./routes/universities/zjut/index
router.get('/zjut/design/:type', lazyloadRouteHandler('./routes/universities/zjut/design'));
// 上海大学
router.get('/shu/:type?', lazyloadRouteHandler('./routes/universities/shu/index'));
router.get('/shu/jwc/:type?', lazyloadRouteHandler('./routes/universities/shu/jwc'));
// router.get('/shu/:type?', lazyloadRouteHandler('./routes/universities/shu/index'));
// router.get('/shu/jwc/:type?', lazyloadRouteHandler('./routes/universities/shu/jwc'));
// router.get('/shu/jwb/:type?', lazyloadRouteHandler('./routes/universities/shu/jwc'));
// 北京科技大学天津学院
// router.get('/ustb/tj/news/:type?', lazyloadRouteHandler('./routes/universities/ustb/tj/news'));

View File

@ -1,75 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const url = require('url');
const host = 'https://www.shu.edu.cn/';
const config = {
news: {
link: 'https://www.shu.edu.cn/index/zhxw.htm',
title: '综合新闻',
},
research: {
link: 'https://www.shu.edu.cn/index/kydt1.htm',
title: '科研动态',
},
notice: {
link: 'https://www.shu.edu.cn/index/tzgg.htm',
title: '通知公告',
},
};
module.exports = async (ctx) => {
const type = ctx.params.type ? ctx.params.type : 'news';
const link = type === 'news' ? config.news.link : type === 'research' ? config.research.link : config.notice.link;
const title = type === 'news' ? config.news.title : type === 'research' ? config.research.title : config.notice.title;
const respond = await got.get(link);
const $ = cheerio.load(respond.data);
const list = $('.list-con')
.find('li')
.slice(0, 10)
.map((index, ele) => ({
title: $(ele).find('.list-txt-1').text(),
link: $(ele).find('a').attr('href'),
date: $(ele).find('.list-date').text(),
}))
.get();
const all = await Promise.all(
list.map(async (item) => {
const itemUrl = url.resolve(host, item.link);
const cache = await ctx.cache.get(itemUrl);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
let desc = '';
const respond = await got.get(itemUrl);
const $ = cheerio.load(respond.data);
if (type === 'notice') {
desc = $('.content-con').text();
} else {
desc = $('#vsb_content_2').text();
if (desc.length > 256) {
desc = desc.slice(0, 256) + '...';
}
}
const date = new Date(item.date);
const time_zone = 8;
const server_offset = date.getTimezoneOffset() / 60;
const single = {
title: item.title,
link: itemUrl,
pubDate: new Date(date.getTime() - 60 * 60 * 1000 * (time_zone + server_offset)).toUTCString(),
description: desc || item.title,
};
ctx.cache.set(itemUrl, JSON.stringify(single));
return Promise.resolve(single);
})
);
ctx.state.data = {
title: title + ' - 上海大学',
link: 'https://www.shu.edu.cn/',
item: all,
};
};

View File

@ -1,62 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const url = require('url');
const host = 'http://www.jwc.shu.edu.cn';
const config = {
notice: {
link: 'http://www.jwc.shu.edu.cn/nry.jsp?urltype=tree.TreeTempUrl&wbtreeid=1015',
type: 'notice',
title: '通知通告',
},
news: {
link: 'http://www.jwc.shu.edu.cn/nry.jsp?urltype=tree.TreeTempUrl&wbtreeid=1016',
type: 'news',
title: '新闻',
},
};
module.exports = async (ctx) => {
let type = ctx.params.type;
type = type ? type : 'notice';
const link = type === 'news' ? config.news.link : config.notice.link;
const title = type === 'news' ? config.news.title : config.notice.title;
const respond = await got.get(link);
const $ = cheerio.load(respond.data);
const list = $('#dnn_ctr43516_ArticleList__ctl0_ArtDataList__ctl1_titleLink1')
.slice(0, 10)
.map((index, ele) => ({
title: $(ele).attr('title'),
link: $(ele).attr('href'),
date: $('#dnn_ctr43516_ArticleList__ctl0_ArtDataList__ctl1_Label6').text(),
}))
.get();
const all = await Promise.all(
list.map(async (item) => {
const itemUrl = url.resolve(host, item.link);
const cache = await ctx.cache.get(itemUrl);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const respond = await got.get(itemUrl);
const $ = cheerio.load(respond.data);
const single = {
title: item.title,
link: itemUrl,
author: $('.normal').next().text().trim().slice(0, -3),
guid: itemUrl,
pubDate: new Date(new Date(...$('.normal').text().slice(0, 10).split('-')).getTime() - 60 * 60 * 24 * 30 * 1000).toUTCString(),
description: item.title,
};
ctx.cache.set(itemUrl, JSON.stringify(single));
return Promise.resolve(single);
})
);
ctx.state.data = {
title: '上海大学教务处--' + title,
link: 'http://www.jwc.shu.edu.cn/',
item: all,
};
};

48
lib/v2/shu/index.js Normal file
View File

@ -0,0 +1,48 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const host = 'https://www.shu.edu.cn/';
const alias = new Map([
['news', 'zhxw'], // 综合新闻
['research', 'kydt1'], // 科研动态
['kydt', 'kydt1'], // 科研动态
['notice', 'tzgg'], // 通知公告
['important', 'zyxw'], // 重要新闻
]);
module.exports = async (ctx) => {
const type = ctx.params.type || 'news';
const link = `https://www.shu.edu.cn/${alias.get(type) || type}.htm`;
const respond = await got.get(link);
const $ = cheerio.load(respond.data);
const title = $('title').text();
const list = $('.ej_main .list')
.find('li')
.slice(0, 5)
.toArray()
.map((ele) => ({
title: $(ele).find('.bt').text(),
link: new URL($(ele).find('a').attr('href'), host).href,
date: $(ele).find('.sj').text(),
}));
const all = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const response = await got.get(item.link);
const $ = cheerio.load(response.data);
item.author = $('.xx>:nth-child(2)').text().trim().slice(3); // 投稿xxx
item.pubDate = parseDate(item.date, 'YYYY.MM.DD');
item.description = $('.v_news_content').html() || item.title;
return item;
})
)
);
ctx.state.data = {
title,
link,
item: all,
};
};

45
lib/v2/shu/jwb.js Normal file
View File

@ -0,0 +1,45 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const host = 'https://jwb.shu.edu.cn/';
const alias = new Map([
['notice', 'tzgg'], // 通知公告
['news', 'xw'], // 新闻动态
['policy', 'zcwj'], // 政策文件
]);
module.exports = async (ctx) => {
const type = ctx.params.type || 'notice';
const link = `https://jwb.shu.edu.cn/index/${alias.get(type) || type}.htm`;
const respond = await got.get(link);
const $ = cheerio.load(respond.data);
const title = $('title').text();
const list = $('.only-list')
.find('li')
.slice(0, 10)
.toArray()
.map((ele) => ({
title: $(ele).find('a').text(),
link: new URL($(ele).find('a').attr('href'), host).href,
date: $(ele).children('span').text(),
}));
const all = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const response = await got.get(item.link);
const $ = cheerio.load(response.data);
item.author = $('[id$=_lblUser]').text().trim();
item.pubDate = parseDate(item.date, 'YYYY年MM月DD日');
item.description = $('.v_news_content').html() || item.title;
return item;
})
)
);
ctx.state.data = {
title,
link,
item: all,
};
};

4
lib/v2/shu/maintainer.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
'/:type?': ['lonelyion'],
'/jwb/:type?': ['tuxinghuan'],
};

21
lib/v2/shu/radar.js Normal file
View File

@ -0,0 +1,21 @@
module.exports = {
'shu.edu.cn': {
_name: '上海大学',
jwb: [
{
title: '教务处通知公告',
docs: 'https://docs.rsshub.app/university.html#shang-hai-da-xue',
source: ['/index/:type'],
target: '/shu/jwb/:type',
},
],
www: [
{
title: '官网信息',
docs: 'https://docs.rsshub.app/university.html#shang-hai-da-xue',
source: ['/:type'],
target: '/shu/:type',
},
],
},
};

5
lib/v2/shu/router.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = (router) => {
router.get('/:type?', require('./index'));
router.get('/jwc/:type?', require('./jwb')); // TODO: deprecated, remove this line when someone update this file next time
router.get('/jwb/:type?', require('./jwb'));
};