mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-04 19:59:54 +08:00
feat: add support for BUPT portal (#3290)
This commit is contained in:
@@ -104,6 +104,16 @@ pageClass: routes
|
||||
|
||||
<Route author="RicardoMing" example="/bupt/grs" path="/bupt/grs" />
|
||||
|
||||
### 信息门户
|
||||
|
||||
<Route author="RicardoMing" example="/bupt/portal" path="/bupt/portal" />
|
||||
|
||||
::: warning 注意
|
||||
信息门户的通知需要通过统一身份认证后才能获取,因此需要在校园网或校园 VPN 环境下自建。
|
||||
|
||||
设置环境变量: `BUPT_USERNAME` 用户名为学号, `BUPT_PASSWORD` 统一身份认证的密码。
|
||||
:::
|
||||
|
||||
## 常州大学
|
||||
|
||||
### 教务处
|
||||
|
||||
@@ -98,6 +98,10 @@ const calculateValue = () => {
|
||||
chuiniu: {
|
||||
member: envs.CHUINIU_MEMBER,
|
||||
},
|
||||
bupt: {
|
||||
username: envs.BUPT_USERNAME,
|
||||
password: envs.BUPT_PASSWORD,
|
||||
},
|
||||
};
|
||||
};
|
||||
calculateValue();
|
||||
|
||||
@@ -1309,6 +1309,7 @@ router.get('/21caijing/channel/:name', require('./routes/21caijing/channel'));
|
||||
// 北京邮电大学
|
||||
router.get('/bupt/yz/:type', require('./routes/universities/bupt/yz'));
|
||||
router.get('/bupt/grs', require('./routes/universities/bupt/grs'));
|
||||
router.get('/bupt/portal', require('./routes/universities/bupt/portal'));
|
||||
|
||||
// VOCUS 方格子
|
||||
router.get('/vocus/publication/:id', require('./routes/vocus/publication'));
|
||||
|
||||
172
lib/routes/universities/bupt/portal.js
Normal file
172
lib/routes/universities/bupt/portal.js
Normal file
@@ -0,0 +1,172 @@
|
||||
const config = require('@/config').value;
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const url = require('url');
|
||||
|
||||
function isToday(time) {
|
||||
return new Date().getTime() - new Date(time).getTime() < 86400000;
|
||||
}
|
||||
|
||||
function getPubDate(time) {
|
||||
return isToday(time) ? new Date() : new Date(time + ' 08:00:00');
|
||||
}
|
||||
|
||||
const base = 'http://my.bupt.edu.cn';
|
||||
const sourceTimezoneOffset = -8;
|
||||
|
||||
let portalCookie = null;
|
||||
let authCookie = null;
|
||||
let castgc = null;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
if (!config.bupt || !config.bupt.username || !config.bupt.password) {
|
||||
throw 'BUPT Portal RSS is disabled due to the lack of <a href="https://docs.rsshub.app/university.html#bei-jing-you-dian-da-xue">relevant config</a>';
|
||||
}
|
||||
|
||||
const reqUrl = url.resolve(base, '/index.portal?.pn=p1778');
|
||||
let reqRes = await got({
|
||||
method: 'get',
|
||||
followRedirect: false,
|
||||
url: reqUrl,
|
||||
headers: {
|
||||
cookie: portalCookie,
|
||||
},
|
||||
});
|
||||
|
||||
// Login
|
||||
if (reqRes.statusCode === 302) {
|
||||
if (reqRes.headers['set-cookie'] === undefined) {
|
||||
portalCookie = null;
|
||||
throw 'Can not obtain portalCookie';
|
||||
}
|
||||
portalCookie = reqRes.headers['set-cookie'].toString().match(/JSESSIONID=.{37}/)[0];
|
||||
|
||||
const authRes = await got({
|
||||
method: 'get',
|
||||
followRedirect: false,
|
||||
url: reqRes.headers.location,
|
||||
headers: {
|
||||
cookie: `${authCookie}; ${castgc}`,
|
||||
},
|
||||
});
|
||||
if (authRes.statusCode === 200) {
|
||||
authCookie = authRes.headers['set-cookie'].toString().match(/JSESSIONID=.{37}/)[0];
|
||||
const authPage = cheerio.load(authRes.data);
|
||||
|
||||
const loginRes = await got({
|
||||
method: 'post',
|
||||
followRedirect: false,
|
||||
url: reqRes.headers.location,
|
||||
headers: {
|
||||
cookie: authCookie,
|
||||
referer: reqRes.headers.location,
|
||||
},
|
||||
form: true,
|
||||
data: {
|
||||
username: config.bupt.username,
|
||||
password: config.bupt.password,
|
||||
lt: authPage('[name=lt]').attr('value'),
|
||||
execution: authPage('[name=execution]').attr('value'),
|
||||
_eventId: authPage('[name=_eventId]').attr('value'),
|
||||
rmShown: 1,
|
||||
},
|
||||
});
|
||||
if (loginRes.headers['set-cookie'] === undefined) {
|
||||
authCookie = null;
|
||||
castgc = null;
|
||||
throw 'Can not obtain castgc';
|
||||
}
|
||||
castgc = loginRes.headers['set-cookie'].toString().match(/CASTGC=.{85}/)[0];
|
||||
|
||||
await got({
|
||||
method: 'get',
|
||||
followRedirect: false,
|
||||
url: loginRes.headers.location,
|
||||
headers: {
|
||||
cookie: portalCookie,
|
||||
},
|
||||
});
|
||||
} else if (authRes.statusCode === 302) {
|
||||
await got({
|
||||
method: 'get',
|
||||
followRedirect: false,
|
||||
url: authRes.headers.location,
|
||||
headers: {
|
||||
cookie: portalCookie,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
throw 'BUPT auth login failed';
|
||||
}
|
||||
|
||||
reqRes = await got({
|
||||
method: 'get',
|
||||
followRedirect: false,
|
||||
url: reqUrl,
|
||||
headers: {
|
||||
cookie: portalCookie,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const $ = cheerio.load(reqRes.data);
|
||||
const list = $('.newslist li').get();
|
||||
const out = await Promise.all(
|
||||
list.map(async (i) => {
|
||||
const item = $(i);
|
||||
const itemUrl = url.resolve(
|
||||
base,
|
||||
$(item)
|
||||
.find('a')
|
||||
.attr('href')
|
||||
);
|
||||
const cache = await ctx.cache.get(itemUrl);
|
||||
if (cache) {
|
||||
return Promise.resolve(JSON.parse(cache));
|
||||
}
|
||||
|
||||
const title = $(item)
|
||||
.find('a')
|
||||
.text();
|
||||
const author = $(item)
|
||||
.find('.author')
|
||||
.text();
|
||||
const time = getPubDate(
|
||||
$(item)
|
||||
.find('.time')
|
||||
.text()
|
||||
);
|
||||
time.setTime(time.getTime() + (sourceTimezoneOffset - time.getTimezoneOffset() / 60) * 60 * 60 * 1000);
|
||||
|
||||
const itemResponse = await got({
|
||||
method: 'get',
|
||||
url: itemUrl,
|
||||
headers: {
|
||||
cookie: portalCookie,
|
||||
},
|
||||
});
|
||||
const itemElement = cheerio.load(itemResponse.data);
|
||||
// Remove useless print button
|
||||
itemElement('table.Noprint').remove();
|
||||
const description = itemElement('.singleexpert').html();
|
||||
|
||||
const single = {
|
||||
title: title,
|
||||
author: author,
|
||||
description: description,
|
||||
pubDate: time.toUTCString(),
|
||||
link: itemUrl,
|
||||
guid: itemUrl,
|
||||
};
|
||||
|
||||
ctx.cache.set(itemUrl, JSON.stringify(single));
|
||||
return Promise.resolve(single);
|
||||
})
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: '北京邮电大学信息门户',
|
||||
link: reqUrl,
|
||||
item: out,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user